X-Git-Url: https://git.heureux-cyclage.org/?a=blobdiff_plain;f=includes%2FGlobalFunctions.php;h=3aa22c8753735429a8498948c1dd25157c6357fe;hb=a13e752b69cf306ec7b1be6af007eaafd5ef5d3d;hp=a68daf0fd88c2fde85b320d9e94c14f862cffb99;hpb=d6c6cfd95fd999a11edc99fa83f90e4d4eaf1a21;p=lhc%2Fweb%2Fwiklou.git diff --git a/includes/GlobalFunctions.php b/includes/GlobalFunctions.php index a68daf0fd8..3aa22c8753 100644 --- a/includes/GlobalFunctions.php +++ b/includes/GlobalFunctions.php @@ -1,14 +1,14 @@ 0 ) { if( $splitPos > 256 ) { // Optimize large string offsets by skipping ahead N bytes. // This will cut out most of our slow time on Latin-based text, // and 1/2 to 1/3 on East European and Asian scripts. $bytePos = $splitPos; - while ($bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0") + while ( $bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ) { ++$bytePos; + } $charPos = mb_strlen( substr( $str, 0, $bytePos ) ); } else { $charPos = 0; $bytePos = 0; } - + while( $charPos++ < $splitPos ) { ++$bytePos; // Move past any tail bytes - while ($bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0") + while ( $bytePos < $byteLen && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ) { ++$bytePos; + } } } else { $splitPosX = $splitPos + 1; @@ -91,11 +102,12 @@ if ( !function_exists( 'mb_substr' ) ) { while( $bytePos > 0 && $charPos-- >= $splitPosX ) { --$bytePos; // Move past any tail bytes - while ($bytePos > 0 && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0") + while ( $bytePos > 0 && $str{$bytePos} >= "\x80" && $str{$bytePos} < "\xc0" ) { --$bytePos; + } } } - + return $bytePos; } } @@ -107,7 +119,7 @@ if ( !function_exists( 'mb_strlen' ) ) { * @param string $enc optional encoding; ignored * @return int */ - function mb_strlen( $str, $enc="" ) { + function mb_strlen( $str, $enc = '' ) { $counts = count_chars( $str ); $total = 0; @@ -134,11 +146,11 @@ if( !function_exists( 'mb_strpos' ) ) { * @param $encoding String: optional encoding; ignored * @return int */ - function mb_strpos( $haystack, $needle, $offset = 0, $encoding="" ) { + function mb_strpos( $haystack, $needle, $offset = 0, $encoding = '' ) { $needle = preg_quote( $needle, '/' ); $ar = array(); - preg_match( '/'.$needle.'/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset ); + preg_match( '/' . $needle . '/u', $haystack, $ar, PREG_OFFSET_CAPTURE, $offset ); if( isset( $ar[0][1] ) ) { return $ar[0][1]; @@ -157,18 +169,18 @@ if( !function_exists( 'mb_strrpos' ) ) { * @param $encoding String: optional encoding; ignored * @return int */ - function mb_strrpos( $haystack, $needle, $offset = 0, $encoding = "" ) { + 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 ); + 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]; + 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; - } + } } } @@ -202,7 +214,7 @@ function wfArrayDiff2_cmp( $a, $b ) { } else { reset( $a ); reset( $b ); - while( ( list( $keyA, $valueA ) = each( $a ) ) && ( list( $keyB, $valueB ) = each( $b ) ) ) { + while( ( list( , $valueA ) = each( $a ) ) && ( list( , $valueB ) = each( $b ) ) ) { $cmp = strcmp( $valueA, $valueB ); if ( $cmp !== 0 ) { return $cmp; @@ -212,14 +224,6 @@ function wfArrayDiff2_cmp( $a, $b ) { } } -/** - * Seed Mersenne Twister - * No-op for compatibility; only necessary in PHP < 4.2.0 - */ -function wfSeedRandom() { - /* No-op */ -} - /** * Get a random decimal value between 0 and 1, in a way * not likely to give duplicate values for any realistic @@ -231,7 +235,7 @@ function wfRandom() { # The maximum random value is "only" 2^31-1, so get two random # values to reduce the chance of dupes $max = mt_getrandmax() + 1; - $rand = number_format( (mt_rand() * $max + mt_rand()) + $rand = number_format( ( mt_rand() * $max + mt_rand() ) / $max / $max, 12, '.', '' ); return $rand; } @@ -250,9 +254,9 @@ function wfRandom() { * * ;:@$!*(),/ * - * However, IIS7 redirects fail when the url contains a colon (Bug 22709), + * 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: @@ -261,16 +265,16 @@ function wfRandom() { 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 = 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( $needle, - array( ';', '@', '$', '!', '*', '(', ')', ',', '/', ':' ), + array( ';', '@', '$', '!', '*', '(', ')', ',', '/', ':' ), $s ); @@ -293,7 +297,6 @@ function wfUrlencode( $s ) { function wfDebug( $text, $logonly = false ) { global $wgOut, $wgDebugLogFile, $wgDebugComments, $wgProfileOnly, $wgDebugRawPage; global $wgDebugLogPrefix, $wgShowDebug; - static $recursion = 0; static $cache = array(); // Cache of unoutputted messages $text = wfDebugTimer() . $text; @@ -306,21 +309,11 @@ function wfDebug( $text, $logonly = false ) { if ( ( $wgDebugComments || $wgShowDebug ) && !$logonly ) { $cache[] = $text; - if ( !isset( $wgOut ) ) { - return; + if ( isset( $wgOut ) && StubObject::isRealObject( $wgOut ) ) { + // add the message and any cached messages to the output + array_map( array( $wgOut, 'debug' ), $cache ); + $cache = array(); } - if ( !StubObject::isRealObject( $wgOut ) ) { - if ( $recursion ) { - return; - } - $recursion++; - $wgOut->_unstub(); - $recursion--; - } - - // add the message and possible cached ones to the output - array_map( array( $wgOut, 'debug' ), $cache ); - $cache = array(); } if ( $wgDebugLogFile != '' && !$wgProfileOnly ) { # Strip unprintables; they can switch terminal modes when binary data @@ -333,7 +326,9 @@ function wfDebug( $text, $logonly = false ) { function wfDebugTimer() { global $wgDebugTimestamps; - if ( !$wgDebugTimestamps ) return ''; + if ( !$wgDebugTimestamps ) { + return ''; + } static $start = null; if ( $start === null ) { @@ -371,7 +366,7 @@ function wfDebugMem( $exact = false ) { */ function wfDebugLog( $logGroup, $text, $public = true ) { global $wgDebugLogGroups, $wgShowHostnames; - $text = trim($text)."\n"; + $text = trim( $text ) . "\n"; if( isset( $wgDebugLogGroups[$logGroup] ) ) { $time = wfTimestamp( TS_DB ); $wiki = wfWikiID(); @@ -381,7 +376,7 @@ function wfDebugLog( $logGroup, $text, $public = true ) { $host = ''; } wfErrorLog( "$time $host $wiki: $text", $wgDebugLogGroups[$logGroup] ); - } else if ( $public === true ) { + } elseif ( $public === true ) { wfDebug( $text, true ); } } @@ -394,28 +389,27 @@ function wfLogDBError( $text ) { global $wgDBerrorLog, $wgDBname; if ( $wgDBerrorLog ) { $host = trim(`hostname`); - $text = date('D M j G:i:s T Y') . "\t$host\t$wgDBname\t$text"; + $text = date( 'D M j G:i:s T Y' ) . "\t$host\t$wgDBname\t$text"; wfErrorLog( $text, $wgDBerrorLog ); } } /** * Log to a file without getting "file size exceeded" signals. - * - * Can also log to TCP or UDP with the syntax udp://host:port/prefix. This will + * + * Can also log to TCP or UDP with the syntax udp://host:port/prefix. This will * send lines to the specified port, prefixed by the specified prefix and a space. */ function wfErrorLog( $text, $file ) { if ( substr( $file, 0, 4 ) == 'udp:' ) { + # Needs the sockets extension if ( preg_match( '!^(tcp|udp):(?://)?\[([0-9a-fA-F:]+)\]:(\d+)(?:/(.*))?$!', $file, $m ) ) { // IPv6 bracketed host - $protocol = $m[1]; $host = $m[2]; $port = intval( $m[3] ); $prefix = isset( $m[4] ) ? $m[4] : false; $domain = AF_INET6; } elseif ( preg_match( '!^(tcp|udp):(?://)?([a-zA-Z0-9.-]+):(\d+)(?:/(.*))?$!', $file, $m ) ) { - $protocol = $m[1]; $host = $m[2]; if ( !IP::isIPv4( $host ) ) { $host = gethostbyname( $host ); @@ -424,7 +418,7 @@ function wfErrorLog( $text, $file ) { $prefix = isset( $m[4] ) ? $m[4] : false; $domain = AF_INET; } else { - throw new MWException( __METHOD__.": Invalid UDP specification" ); + throw new MWException( __METHOD__ . ': Invalid UDP specification' ); } // Clean it up for the multiplexer if ( strval( $prefix ) !== '' ) { @@ -458,29 +452,39 @@ function wfLogProfilingData() { global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest; global $wgProfiler, $wgProfileLimit, $wgUser; # Profiling must actually be enabled... - if( is_null( $wgProfiler ) ) return; + if( is_null( $wgProfiler ) ) { + return; + } # Get total page request time $now = wfTime(); $elapsed = $now - $wgRequestTime; # Only show pages that longer than $wgProfileLimit time (default is 0) - if( $elapsed <= $wgProfileLimit ) return; + if( $elapsed <= $wgProfileLimit ) { + return; + } $prof = wfGetProfilingOutput( $wgRequestTime, $elapsed ); $forward = ''; - if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) + if( !empty( $_SERVER['HTTP_X_FORWARDED_FOR'] ) ) { $forward = ' forwarded for ' . $_SERVER['HTTP_X_FORWARDED_FOR']; - if( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) + } + if( !empty( $_SERVER['HTTP_CLIENT_IP'] ) ) { $forward .= ' client IP ' . $_SERVER['HTTP_CLIENT_IP']; - if( !empty( $_SERVER['HTTP_FROM'] ) ) + } + if( !empty( $_SERVER['HTTP_FROM'] ) ) { $forward .= ' from ' . $_SERVER['HTTP_FROM']; - if( $forward ) + } + if( $forward ) { $forward = "\t(proxied via {$_SERVER['REMOTE_ADDR']}{$forward})"; + } // Don't unstub $wgUser at this late stage just for statistics purposes - if( StubObject::isRealObject($wgUser) && $wgUser->isAnon() ) + // FIXME: We can detect some anons even if it is not loaded. See User::getId() + if( $wgUser->mDataLoaded && $wgUser->isAnon() ) { $forward .= ' anon'; + } $log = sprintf( "%s\t%04.3f\t%s\n", - gmdate( 'YmdHis' ), $elapsed, - urldecode( $wgRequest->getRequestURL() . $forward ) ); - if ( $wgDebugLogFile != '' && ( $wgRequest->getVal('action') != 'raw' || $wgDebugRawPage ) ) { + gmdate( 'YmdHis' ), $elapsed, + urldecode( $wgRequest->getRequestURL() . $forward ) ); + if ( $wgDebugLogFile != '' && ( $wgRequest->getVal( 'action' ) != 'raw' || $wgDebugRawPage ) ) { wfErrorLog( $log . $prof, $wgDebugLogFile ); } } @@ -535,14 +539,14 @@ function wfGetLangObj( $langcode = false ) { # Great, we already have the object (hopefully)! return $langcode; } - + 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 === false || $langcode === $wgLang->getCode() ) { # $langcode is the language code of user language object. @@ -561,9 +565,34 @@ function wfGetLangObj( $langcode = false ) { return $wgContLang; } +/** + * Use this instead of $wgContLang, when working with user interface. + * User interface is currently hard coded according to wiki content language + * in many ways, especially regarding to text direction. There is lots stuff + * to fix, hence this function to keep the old behaviour unless the global + * $wgBetterDirectionality is enabled (or removed when everything works). + */ function wfUILang() { global $wgBetterDirectionality; - return wfGetLangObj( $wgBetterDirectionality ? false: true ); + return wfGetLangObj( !$wgBetterDirectionality ); +} + +/** + * This is the new function for getting translated interface messages. + * See the Message class for documentation how to use them. + * The intention is that this function replaces all old wfMsg* functions. + * @param $key \string Message key. + * Varargs: normal message parameters. + * @return \type{Message} + * @since 1.17 + */ +function wfMessage( $key /*...*/) { + $params = func_get_args(); + array_shift( $params ); + if ( isset( $params[0] ) && is_array( $params[0] ) ) { + $params = $params[0]; + } + return new Message( $key, $params ); } /** @@ -576,7 +605,7 @@ function wfUILang() { * defined in languages/Language.php * * This function also takes extra optional parameters (not - * shown in the function definition), which can by used to + * shown in the function definition), which can be used to * insert variable text into the predefined message. */ function wfMsg( $key ) { @@ -598,7 +627,7 @@ function wfMsgNoTrans( $key ) { * Get a message from anywhere, for the current global language * set with $wgLanguageCode. * - * Use this if the message should NOT change dependent on the + * Use this if the message should NOT change dependent on the * language set in the user's preferences. This is the case for * most text written into logs, as well as link targets (such as * the name of the copyright policy page). Link titles, on the @@ -623,7 +652,9 @@ function wfMsgForContent( $key ) { $forcontent = true; if( is_array( $wgForceUIMsgAsContentMsg ) && in_array( $key, $wgForceUIMsgAsContentMsg ) ) + { $forcontent = false; + } return wfMsgReal( $key, $args, true, $forcontent ); } @@ -637,7 +668,9 @@ function wfMsgForContentNoTrans( $key ) { $forcontent = true; if( is_array( $wgForceUIMsgAsContentMsg ) && in_array( $key, $wgForceUIMsgAsContentMsg ) ) + { $forcontent = false; + } return wfMsgReal( $key, $args, true, $forcontent, false ); } @@ -660,7 +693,9 @@ function wfMsgNoDBForContent( $key ) { $forcontent = true; if( is_array( $wgForceUIMsgAsContentMsg ) && in_array( $key, $wgForceUIMsgAsContentMsg ) ) + { $forcontent = false; + } return wfMsgReal( $key, $args, false, $forcontent ); } @@ -688,10 +723,11 @@ function wfMsgReal( $key, $args, $useDB = true, $forContent = false, $transform */ function wfMsgWeirdKey( $key ) { $source = wfMsgGetKey( $key, false, true, false ); - if ( wfEmptyMsg( $key, $source ) ) - return ""; - else + if ( wfEmptyMsg( $key, $source ) ) { + return ''; + } else { return $source; + } } /** @@ -704,16 +740,16 @@ function wfMsgWeirdKey( $key ) { * @return string */ function wfMsgGetKey( $key, $useDB, $langCode = false, $transform = true ) { - global $wgContLang, $wgMessageCache; + global $wgMessageCache; + + wfRunHooks( 'NormalizeMessageKey', array( &$key, &$useDB, &$langCode, &$transform ) ); - wfRunHooks('NormalizeMessageKey', array(&$key, &$useDB, &$langCode, &$transform)); - if ( !is_object( $wgMessageCache ) ) { - throw new MWException( "Trying to get message before message cache is initialised" ); + throw new MWException( 'Trying to get message before message cache is initialised' ); } $message = $wgMessageCache->get( $key, $useDB, $langCode ); - if( $message === false ){ + if( $message === false ) { $message = '<' . htmlspecialchars( $key ) . '>'; } elseif ( $transform ) { $message = $wgMessageCache->transform( $message ); @@ -741,7 +777,7 @@ function wfMsgReplaceArgs( $message, $args ) { } $replacementKeys = array(); foreach( $args as $n => $param ) { - $replacementKeys['$' . ($n + 1)] = $param; + $replacementKeys['$' . ( $n + 1 )] = $param; } $message = strtr( $message, $replacementKeys ); } @@ -788,8 +824,8 @@ function wfMsgWikiHtml( $key ) { * Returns message in the requested format * @param $key String: key of the message * @param $options Array: processing rules. Can take the following options: - * parse: parses wikitext to html - * parseinline: parses wikitext to html and removes the surrounding + * parse: parses wikitext to HTML + * parseinline: parses wikitext to HTML and removes the surrounding * p's added by parser or tidy * escape: filters message through htmlspecialchars * escapenoentities: same, but allows entity references like through @@ -798,7 +834,7 @@ function wfMsgWikiHtml( $key ) { * content: fetch message for content language instead of interface * Also can accept a single associative argument, of the form 'language' => 'xx': * language: Language object or language code to fetch message for - * (overriden by content), its behaviour with parser, parseinline + * (overriden by content), its behaviour with parse, parseinline * and parsemag is undefined. * Behavior for conflicting options (e.g., parse+parseinline) is undefined. */ @@ -822,10 +858,10 @@ function wfMsgExt( $key, $options ) { } } - if( in_array('content', $options, true ) ) { + if( in_array( 'content', $options, true ) ) { $forContent = true; $langCode = true; - } elseif( array_key_exists('language', $options) ) { + } elseif( array_key_exists( 'language', $options ) ) { $forContent = false; $langCode = wfGetLangObj( $options['language'] ); } else { @@ -835,19 +871,19 @@ function wfMsgExt( $key, $options ) { $string = wfMsgGetKey( $key, /*DB*/true, $langCode, /*Transform*/false ); - if( !in_array('replaceafter', $options, true ) ) { + if( !in_array( 'replaceafter', $options, true ) ) { $string = wfMsgReplaceArgs( $string, $args ); } - if( in_array('parse', $options, true ) ) { + if( in_array( 'parse', $options, true ) ) { $string = $wgOut->parse( $string, true, !$forContent ); - } elseif ( in_array('parseinline', $options, true ) ) { + } elseif ( in_array( 'parseinline', $options, true ) ) { $string = $wgOut->parse( $string, true, !$forContent ); $m = array(); if( preg_match( '/^
(.*)\n?<\/p>\n?$/sU', $string, $m ) ) { $string = $m[1]; } - } elseif ( in_array('parsemag', $options, true ) ) { + } elseif ( in_array( 'parsemag', $options, true ) ) { global $wgMessageCache; if ( isset( $wgMessageCache ) ) { $string = $wgMessageCache->transform( $string, @@ -856,13 +892,13 @@ function wfMsgExt( $key, $options ) { } } - if ( in_array('escape', $options, true ) ) { + if ( in_array( 'escape', $options, true ) ) { $string = htmlspecialchars ( $string ); - } elseif ( in_array( 'escapenoentities', $options, true ) ) { + } elseif ( in_array( 'escapenoentities', $options, true ) ) { $string = Sanitizer::escapeHtmlAllowEntities( $string ); } - if( in_array('replaceafter', $options, true ) ) { + if( in_array( 'replaceafter', $options, true ) ) { $string = wfMsgReplaceArgs( $string, $args ); } @@ -874,24 +910,26 @@ function wfMsgExt( $key, $options ) { * Just like exit() but makes a note of it. * Commits open transactions except if the error parameter is set * - * @deprecated Please return control to the caller or throw an exception + * @deprecated Please return control to the caller or throw an exception. Will + * be removed in 1.19. */ -function wfAbruptExit( $error = false ){ +function wfAbruptExit( $error = false ) { static $called = false; - if ( $called ){ + if ( $called ) { exit( -1 ); } $called = true; + wfDeprecated( __FUNCTION__ ); $bt = wfDebugBacktrace(); if( $bt ) { - for($i = 0; $i < count($bt) ; $i++){ - $file = isset($bt[$i]['file']) ? $bt[$i]['file'] : "unknown"; - $line = isset($bt[$i]['line']) ? $bt[$i]['line'] : "unknown"; - wfDebug("WARNING: Abrupt exit in $file at line $line\n"); + for( $i = 0; $i < count( $bt ); $i++ ) { + $file = isset( $bt[$i]['file'] ) ? $bt[$i]['file'] : 'unknown'; + $line = isset( $bt[$i]['line'] ) ? $bt[$i]['line'] : 'unknown'; + wfDebug( "WARNING: Abrupt exit in $file at line $line\n"); } } else { - wfDebug("WARNING: Abrupt exit\n"); + wfDebug( "WARNING: Abrupt exit\n" ); } wfLogProfilingData(); @@ -903,9 +941,11 @@ function wfAbruptExit( $error = false ){ } /** - * @deprecated Please return control the caller or throw an exception + * @deprecated Please return control the caller or throw an exception. Will + * be removed in 1.19. */ function wfErrorExit() { + wfDeprecated( __FUNCTION__ ); wfAbruptExit( true ); } @@ -914,7 +954,7 @@ function wfErrorExit() { * Plain die() fails to return nonzero to the shell if you pass a string. * @param $msg String */ -function wfDie( $msg='' ) { +function wfDie( $msg = '' ) { echo $msg; die( 1 ); } @@ -969,8 +1009,8 @@ function wfReportTime() { $elapsed = $now - $wgRequestTime; return $wgShowHostnames - ? sprintf( "", wfHostname(), $elapsed ) - : sprintf( "", $elapsed ); + ? sprintf( '', wfHostname(), $elapsed ) + : sprintf( '', $elapsed ); } /** @@ -1023,7 +1063,7 @@ function wfBacktrace() { foreach( $backtrace as $call ) { if( isset( $call['file'] ) ) { $f = explode( DIRECTORY_SEPARATOR, $call['file'] ); - $file = $f[count($f)-1]; + $file = $f[count( $f ) - 1]; } else { $file = '-'; } @@ -1037,7 +1077,9 @@ function wfBacktrace() { } else { $msg .= '
" . + '
' . nl2br( htmlspecialchars( $desc ) ) . "
\n"; } @@ -1620,7 +1675,7 @@ function wfHttpError( $code, $label, $desc ) { * * @param $resetGzipEncoding Bool */ -function wfResetOutputBuffers( $resetGzipEncoding=true ) { +function wfResetOutputBuffers( $resetGzipEncoding = true ) { if( $resetGzipEncoding ) { // Suppress Content-Encoding and Content-Length // headers from 1.10+s wfOutputHandler @@ -1689,7 +1744,7 @@ function wfAcceptToPrefs( $accept, $def = '*/*' ) { if( !isset( $qpart ) ) { $prefs[$value] = 1.0; } elseif( preg_match( '/q\s*=\s*(\d*\.\d+)/', $qpart, $match ) ) { - $prefs[$value] = floatval($match[1]); + $prefs[$value] = floatval( $match[1] ); } } @@ -1709,7 +1764,7 @@ function wfAcceptToPrefs( $accept, $def = '*/*' ) { * @private */ function mimeTypeMatch( $type, $avail ) { - if( array_key_exists($type, $avail) ) { + if( array_key_exists( $type, $avail ) ) { return $type; } else { $parts = explode( '/', $type ); @@ -1826,29 +1881,29 @@ function wfRestoreWarnings() { /** * Unix time - the number of seconds since 1970-01-01 00:00:00 UTC */ -define('TS_UNIX', 0); +define( 'TS_UNIX', 0 ); /** * MediaWiki concatenated string timestamp (YYYYMMDDHHMMSS) */ -define('TS_MW', 1); +define( 'TS_MW', 1 ); /** * MySQL DATETIME (YYYY-MM-DD HH:MM:SS) */ -define('TS_DB', 2); +define( 'TS_DB', 2 ); /** * RFC 2822 format, for E-mail and HTTP headers */ -define('TS_RFC2822', 3); +define( 'TS_RFC2822', 3 ); /** * ISO 8601 format with no timezone: 1986-02-09T20:00:00Z * * This is used by Special:Export */ -define('TS_ISO_8601', 4); +define( 'TS_ISO_8601', 4 ); /** * An Exif timestamp (YYYY:MM:DD HH:MM:SS) @@ -1857,91 +1912,152 @@ define('TS_ISO_8601', 4); * DateTime tag and page 36 for the DateTimeOriginal and * DateTimeDigitized tags. */ -define('TS_EXIF', 5); +define( 'TS_EXIF', 5 ); /** * Oracle format time. */ -define('TS_ORACLE', 6); +define( 'TS_ORACLE', 6 ); /** * Postgres format time. */ -define('TS_POSTGRES', 7); +define( 'TS_POSTGRES', 7 ); /** * DB2 format time */ -define('TS_DB2', 8); +define( 'TS_DB2', 8 ); + +/** + * ISO 8601 basic format with no timezone: 19860209T200000Z + * + * This is used by ResourceLoader + */ +define( 'TS_ISO_8601_BASIC', 9 ); /** * @param $outputtype Mixed: A timestamp in one of the supported formats, the * function will autodetect which format is supplied and act * accordingly. * @param $ts Mixed: the timestamp to convert or 0 for the current timestamp - * @return String: in the format specified in $outputtype + * @return Mixed: String / false The same date in the format specified in $outputtype or false */ function wfTimestamp( $outputtype = TS_UNIX, $ts = 0 ) { $uts = 0; $da = array(); - if ($ts==0) { - $uts=time(); - } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)$/D',$ts,$da)) { + $strtime = ''; + + if ( $ts === 0 ) { + $uts = time(); + $strtime = "@$uts"; + } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) { # TS_DB - } elseif (preg_match('/^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/D',$ts,$da)) { + } elseif ( preg_match( '/^(\d{4}):(\d\d):(\d\d) (\d\d):(\d\d):(\d\d)$/D', $ts, $da ) ) { # TS_EXIF - } elseif (preg_match('/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/D',$ts,$da)) { + } elseif ( preg_match( '/^(\d{4})(\d\d)(\d\d)(\d\d)(\d\d)(\d\d)$/D', $ts, $da ) ) { # TS_MW - } elseif (preg_match('/^-?\d{1,13}$/D',$ts)) { + } elseif ( preg_match( '/^-?\d{1,13}$/D', $ts ) ) { # TS_UNIX $uts = $ts; - } elseif (preg_match('/^\d{2}-\d{2}-\d{4} \d{2}:\d{2}:\d{2}.\d{6}$/', $ts)) { + $strtime = "@$ts"; // Undocumented? + } 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)) { + $strtime = 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 ) ) { # TS_ISO_8601 - } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/',$ts,$da)) { + } elseif ( preg_match( '/^(\d{4})(\d{2})(\d{2})T(\d{2})(\d{2})(\d{2})(?:\.*\d*)?Z$/', $ts, $da ) ) { + #TS_ISO_8601_BASIC + } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d*[\+\- ](\d\d)$/', $ts, $da ) ) { # TS_POSTGRES - } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/',$ts,$da)) { + } elseif ( preg_match( '/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.*\d* GMT$/', $ts, $da ) ) { # TS_POSTGRES + } elseif (preg_match('/^(\d{4})\-(\d\d)\-(\d\d) (\d\d):(\d\d):(\d\d)\.\d\d\d$/',$ts,$da)) { + # TS_DB2 + } elseif ( preg_match( '/^[ \t\r\n]*([A-Z][a-z]{2},[ \t\r\n]*)?' . # Day of week + '\d\d?[ \t\r\n]*[A-Z][a-z]{2}[ \t\r\n]*\d{2}(?:\d{2})?' . # dd Mon yyyy + '[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d[ \t\r\n]*:[ \t\r\n]*\d\d/S', $ts ) ) { # hh:mm:ss + # TS_RFC2822, accepting a trailing comment. See http://www.squid-cache.org/mail-archive/squid-users/200307/0122.html / r77171 + # The regex is a superset of rfc2822 for readability + $strtime = strtok( $ts, ';' ); + } elseif ( preg_match( '/^[A-Z][a-z]{5,8}, \d\d-[A-Z][a-z]{2}-\d{2} \d\d:\d\d:\d\d/', $ts ) ) { + # TS_RFC850 + $strtime = $ts; + } elseif ( preg_match( '/^[A-Z][a-z]{2} [A-Z][a-z]{2} +\d{1,2} \d\d:\d\d:\d\d \d{4}/', $ts ) ) { + # asctime + $strtime = $ts; } else { # Bogus value; fall back to the epoch... - wfDebug("wfTimestamp() fed bogus time value: $outputtype; $ts\n"); - $uts = 0; + wfDebug("wfTimestamp() fed bogus time value: TYPE=$outputtype; VALUE=$ts\n"); + + return false; } - if (count( $da ) ) { - // Warning! gmmktime() acts oddly if the month or day is set to 0 - // We may want to handle that explicitly at some point - $uts=gmmktime((int)$da[4],(int)$da[5],(int)$da[6], - (int)$da[2],(int)$da[3],(int)$da[1]); + + + static $formats = array( + TS_UNIX => 'U', + TS_MW => 'YmdHis', + TS_DB => 'Y-m-d H:i:s', + TS_ISO_8601 => 'Y-m-d\TH:i:s\Z', + TS_ISO_8601_BASIC => 'Ymd\THis\Z', + TS_EXIF => 'Y:m:d H:i:s', // This shouldn't ever be used, but is included for completeness + TS_RFC2822 => 'D, d M Y H:i:s', + TS_ORACLE => 'd-m-Y H:i:s.000000', // Was 'd-M-y h.i.s A' . ' +00:00' before r51500 + TS_POSTGRES => 'Y-m-d H:i:s', + TS_DB2 => 'Y-m-d H:i:s', + ); + + if ( !isset( $formats[$outputtype] ) ) { + throw new MWException( 'wfTimestamp() called with illegal output type.' ); } - switch($outputtype) { - case TS_UNIX: + if ( function_exists( "date_create" ) ) { + if ( count( $da ) ) { + $ds = sprintf("%04d-%02d-%02dT%02d:%02d:%02d.00+00:00", + (int)$da[1], (int)$da[2], (int)$da[3], + (int)$da[4], (int)$da[5], (int)$da[6]); + + $d = date_create( $ds, new DateTimeZone( 'GMT' ) ); + } elseif ( $strtime ) { + $d = date_create( $strtime, new DateTimeZone( 'GMT' ) ); + } else { + return false; + } + + if ( !$d ) { + wfDebug("wfTimestamp() fed bogus time value: $outputtype; $ts\n"); + return false; + } + + $output = $d->format( $formats[$outputtype] ); + } else { + if ( count( $da ) ) { + // Warning! gmmktime() acts oddly if the month or day is set to 0 + // We may want to handle that explicitly at some point + $uts = gmmktime( (int)$da[4], (int)$da[5], (int)$da[6], + (int)$da[2], (int)$da[3], (int)$da[1] ); + } elseif ( $strtime ) { + $uts = strtotime( $strtime ); + } + + if ( $uts === false ) { + wfDebug("wfTimestamp() can't parse the timestamp (non 32-bit time? Update php): $outputtype; $ts\n"); + return false; + } + + if ( TS_UNIX == $outputtype ) { return $uts; - case TS_MW: - return gmdate( 'YmdHis', $uts ); - case TS_DB: - return gmdate( 'Y-m-d H:i:s', $uts ); - case TS_ISO_8601: - return gmdate( 'Y-m-d\TH:i:s\Z', $uts ); - // This shouldn't ever be used, but is included for completeness - case TS_EXIF: - return gmdate( 'Y:m:d H:i:s', $uts ); - 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.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: - return gmdate( 'Y-m-d H:i:s', $uts); - default: - throw new MWException( 'wfTimestamp() called with illegal output type.'); + } + $output = gmdate( $formats[$outputtype], $uts ); + } + + if ( ( $outputtype == TS_RFC2822 ) || ( $outputtype == TS_POSTGRES ) ) { + $output .= ' GMT'; } + + return $output; } /** @@ -1965,11 +2081,11 @@ function wfTimestampOrNull( $outputtype = TS_UNIX, $ts = null ) { * @return Bool: true if it's Windows, False otherwise. */ function wfIsWindows() { - if (substr(php_uname(), 0, 7) == 'Windows') { - return true; - } else { - return false; + static $isWindows = null; + if ( $isWindows === null ) { + $isWindows = substr( php_uname(), 0, 7 ) == 'Windows'; } + return $isWindows; } /** @@ -2023,11 +2139,11 @@ function wfGetCachedNotice( $name ) { $parserMemc->set( $key, array( 'html' => $parsed, 'hash' => md5( $notice ) ), 600 ); $notice = $parsed; } else { - wfDebug( 'wfGetCachedNotice called for ' . $name . ' with no $wgOut available'."\n" ); + wfDebug( 'wfGetCachedNotice called for ' . $name . ' with no $wgOut available' . "\n" ); $notice = ''; } } - $notice = '<" ) { - $namespaceNotice = '
"; + if ( $namespaceNotice && substr( $namespaceNotice, 0, 7 ) != '<' ) { + $namespaceNotice = '
'; } else { - $namespaceNotice = ""; + $namespaceNotice = ''; } wfProfileOut( $fname ); @@ -2055,7 +2172,7 @@ function wfGetNamespaceNotice() { } function wfGetSiteNotice() { - global $wgUser, $wgSiteNotice; + global $wgUser; $fname = 'wfGetSiteNotice'; wfProfileIn( $fname ); $siteNotice = ''; @@ -2083,7 +2200,7 @@ function wfGetSiteNotice() { /** * BC wrapper for MimeMagic::singleton() - * @deprecated + * @deprecated No longer needed as of 1.17 (r68836). Remove in 1.19. */ function &wfGetMimeMagic() { wfDeprecated( __FUNCTION__ ); @@ -2091,33 +2208,34 @@ function &wfGetMimeMagic() { } /** - * 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. + * Tries to get the system directory for temporary files. The TMPDIR, TMP, and + * TEMP environment variables are then checked in sequence, and if none are set + * try sys_get_temp_dir() for PHP >= 5.2.1. All else fails, return /tmp for Unix + * or C:\Windows\Temp for Windows and hope for the best. + * It is common to call it with tempnam(). * - * NOTE: When possible, use the tempnam() function to create temporary - * files to avoid race conditions on file creation, etc. + * NOTE: When possible, use instead the tmpfile() 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 ) ) { return $tmp; } } - # Hope this is Unix of some kind! - return '/tmp'; + if( function_exists( 'sys_get_temp_dir' ) ) { + return sys_get_temp_dir(); + } + # Usual defaults + return wfIsWindows() ? 'C:\Windows\Temp' : '/tmp'; } /** * Make directory, and make all parent directories if they don't exist - * + * * @param $dir String: full path to directory to create * @param $mode Integer: chmod value to use, default is $wgDirectoryMode * @param $caller String: optional caller param for debugging. @@ -2130,17 +2248,19 @@ function wfMkdirParents( $dir, $mode = null, $caller = null ) { wfDebug( "$caller: called wfMkdirParents($dir)" ); } - if( strval( $dir ) === '' || file_exists( $dir ) ) + if( strval( $dir ) === '' || file_exists( $dir ) ) { return true; + } $dir = str_replace( array( '\\', '/' ), DIRECTORY_SEPARATOR, $dir ); - if ( is_null( $mode ) ) + 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 + $ok = mkdir( $dir, $mode, true ); // PHP5 <3 wfRestoreWarnings(); if( !$ok ) { @@ -2159,13 +2279,29 @@ function wfIncrStats( $key ) { if( $wgStatsMethod == 'udp' ) { global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgDBname; static $socket; - if (!$socket) { - $socket=socket_create(AF_INET, SOCK_DGRAM, SOL_UDP); - $statline="stats/{$wgDBname} - 1 1 1 1 1 -total\n"; - socket_sendto($socket,$statline,strlen($statline),0,$wgUDPProfilerHost,$wgUDPProfilerPort); + if ( !$socket ) { + $socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP ); + $statline = "stats/{$wgDBname} - 1 1 1 1 1 -total\n"; + socket_sendto( + $socket, + $statline, + strlen( $statline ), + 0, + $wgUDPProfilerHost, + $wgUDPProfilerPort + ); } - $statline="stats/{$wgDBname} - 1 1 1 1 1 {$key}\n"; - @socket_sendto($socket,$statline,strlen($statline),0,$wgUDPProfilerHost,$wgUDPProfilerPort); + $statline = "stats/{$wgDBname} - 1 1 1 1 1 {$key}\n"; + wfSuppressWarnings(); + socket_sendto( + $socket, + $statline, + strlen( $statline ), + 0, + $wgUDPProfilerHost, + $wgUDPProfilerPort + ); + wfRestoreWarnings(); } elseif( $wgStatsMethod == 'cache' ) { global $wgMemc; $key = wfMemcKey( 'stats', $key ); @@ -2199,7 +2335,7 @@ function wfPercent( $nr, $acc = 2, $round = true ) { function wfEncryptPassword( $userid, $password ) { wfDeprecated(__FUNCTION__); # Just wrap around User::oldCrypt() - return User::oldCrypt($password, $userid); + return User::oldCrypt( $password, $userid ); } /** @@ -2207,7 +2343,7 @@ function wfEncryptPassword( $userid, $password ) { */ function wfAppendToArrayIfNotDefault( $key, $value, $default, &$changed ) { if ( is_null( $changed ) ) { - throw new MWException('GlobalFunctions::wfAppendToArrayIfNotDefault got null'); + throw new MWException( 'GlobalFunctions::wfAppendToArrayIfNotDefault got null' ); } if ( $default[$key] !== $value ) { $changed[$key] = $value; @@ -2240,7 +2376,7 @@ function in_string( $needle, $str ) { function wfSpecialList( $page, $details ) { global $wgContLang; - $details = $details ? ' ' . $wgContLang->getDirMark() . "($details)" : ""; + $details = $details ? ' ' . $wgContLang->getDirMark() . "($details)" : ''; return $page . $details; } @@ -2253,15 +2389,17 @@ function wfUrlProtocols() { global $wgUrlProtocols; static $retval = null; - if ( !is_null( $retval ) ) + if ( !is_null( $retval ) ) { return $retval; + } // Support old-style $wgUrlProtocols strings, for backwards compatibility // with LocalSettings files from 1.5 if ( is_array( $wgUrlProtocols ) ) { $protocols = array(); - foreach ($wgUrlProtocols as $protocol) + foreach ( $wgUrlProtocols as $protocol ) { $protocols[] = preg_quote( $protocol, '/' ); + } $retval = implode( '|', $protocols ); } else { @@ -2329,12 +2467,14 @@ function wfDl( $extension ) { /** * Execute a shell command, with time and memory limits mirrored from the PHP * configuration if supported. - * @param $cmd Command line, properly escaped for shell. + * @param $cmd String Command line, properly escaped for shell. * @param &$retval optional, will receive the program's exit code. * (non-zero is usually failure) + * @param $environ Array optional environment variables which should be + * added to the executed command environment. * @return collected stdout as a string (trailing newlines stripped) */ -function wfShellExec( $cmd, &$retval=null ) { +function wfShellExec( $cmd, &$retval = null, $environ = array() ) { global $IP, $wgMaxShellMemory, $wgMaxShellFileSize, $wgMaxShellTime; static $disabled; @@ -2342,24 +2482,55 @@ function wfShellExec( $cmd, &$retval=null ) { $disabled = false; if( wfIniGetBool( 'safe_mode' ) ) { wfDebug( "wfShellExec can't run in safe_mode, PHP's exec functions are too broken.\n" ); - $disabled = true; - } - $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" ); - $disabled = true; + $disabled = 'safemode'; + } else { + $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" ); + $disabled = 'passthru'; + } } } if ( $disabled ) { $retval = 1; - return "Unable to run external programs in safe mode."; + return $disabled == 'safemode' ? + 'Unable to run external programs in safe mode.' : + 'Unable to run external programs, passthru() is disabled.'; } wfInitShellLocale(); - if ( php_uname( 's' ) == 'Linux' ) { + $envcmd = ''; + foreach( $environ as $k => $v ) { + if ( wfIsWindows() ) { + /* Surrounding a set in quotes (method used by wfEscapeShellArg) makes the quotes themselves + * appear in the environment variable, so we must use carat escaping as documented in + * http://technet.microsoft.com/en-us/library/cc723564.aspx + * Note however that the quote isn't listed there, but is needed, and the parentheses + * are listed there but doesn't appear to need it. + */ + $envcmd .= "set $k=" . preg_replace( '/([&|()<>^"])/', '^\\1', $v ) . ' && '; + } else { + /* Assume this is a POSIX shell, thus required to accept variable assignments before the command + * http://www.opengroup.org/onlinepubs/009695399/utilities/xcu_chap02.html#tag_02_09_01 + */ + $envcmd .= "$k=" . escapeshellarg( $v ) . ' '; + } + } + $cmd = $envcmd . $cmd; + + if ( wfIsWindows() ) { + if ( version_compare( PHP_VERSION, '5.3.0', '<' ) && /* Fixed in 5.3.0 :) */ + ( version_compare( PHP_VERSION, '5.2.1', '>=' ) || php_uname( 's' ) == 'Windows NT' ) ) + { + # Hack to work around PHP's flawed invocation of cmd.exe + # http://news.php.net/php.internals/21796 + # Windows 9x doesn't accept any kind of quotes + $cmd = '"' . $cmd . '"'; + } + } elseif ( php_uname( 's' ) == 'Linux' ) { $time = intval( $wgMaxShellTime ); $mem = intval( $wgMaxShellMemory ); $filesize = intval( $wgMaxShellFileSize ); @@ -2367,16 +2538,9 @@ function wfShellExec( $cmd, &$retval=null ) { if ( $time > 0 && $mem > 0 ) { $script = "$IP/bin/ulimit4.sh"; if ( is_executable( $script ) ) { - $cmd = escapeshellarg( $script ) . " $time $mem $filesize " . escapeshellarg( $cmd ); + $cmd = '/bin/bash ' . escapeshellarg( $script ) . " $time $mem $filesize " . escapeshellarg( $cmd ); } } - } elseif ( php_uname( 's' ) == 'Windows NT' && - version_compare( PHP_VERSION, '5.3.0', '<' ) ) - { - # This is a hack to work around PHP's flawed invocation of cmd.exe - # http://news.php.net/php.internals/21796 - # Which is fixed in 5.3.0 :) - $cmd = '"' . $cmd . '"'; } wfDebug( "wfShellExec: $cmd\n" ); @@ -2398,7 +2562,9 @@ function wfShellExec( $cmd, &$retval=null ) { */ function wfInitShellLocale() { static $done = false; - if ( $done ) return; + if ( $done ) { + return; + } $done = true; global $wgShellLocale; if ( !wfIniGetBool( 'safe_mode' ) ) { @@ -2425,8 +2591,9 @@ function wfInitShellLocale() { function wfUsePHP( $req_ver ) { $php_ver = PHP_VERSION; - if ( version_compare( $php_ver, (string)$req_ver, '<' ) ) - throw new MWException( "PHP $req_ver required--this is only $php_ver" ); + if ( version_compare( $php_ver, (string)$req_ver, '<' ) ) { + throw new MWException( "PHP $req_ver required--this is only $php_ver" ); + } } /** @@ -2445,8 +2612,9 @@ function wfUsePHP( $req_ver ) { function wfUseMW( $req_ver ) { global $wgVersion; - if ( version_compare( $wgVersion, (string)$req_ver, '<' ) ) + if ( version_compare( $wgVersion, (string)$req_ver, '<' ) ) { throw new MWException( "MediaWiki $req_ver required--this is only $wgVersion" ); + } } /** @@ -2461,8 +2629,8 @@ function wfUseMW( $req_ver ) { * @param $suffix String: to remove if present * @return String */ -function wfBaseName( $path, $suffix='' ) { - $encSuffix = ($suffix == '') +function wfBaseName( $path, $suffix = '' ) { + $encSuffix = ( $suffix == '' ) ? '' : ( '(?:' . preg_quote( $suffix, '#' ) . ')?' ); $matches = array(); @@ -2491,7 +2659,7 @@ function wfRelativePath( $path, $from ) { $path = rtrim( $path, DIRECTORY_SEPARATOR ); $from = rtrim( $from, DIRECTORY_SEPARATOR ); - $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) ); + $pieces = explode( DIRECTORY_SEPARATOR, dirname( $path ) ); $against = explode( DIRECTORY_SEPARATOR, $from ); if( $pieces[0] !== $against[0] ) { @@ -2539,14 +2707,14 @@ function wfArrayMerge( $array1/* ... */ ) { /** * Merge arrays in the style of getUserPermissionsErrors, with duplicate removal * e.g. - * wfMergeErrorArrays( - * array( array( 'x' ) ), - * array( array( 'x', '2' ) ), - * array( array( 'x' ) ), + * wfMergeErrorArrays( + * array( array( 'x' ) ), + * array( array( 'x', '2' ) ), + * array( array( 'x' ) ), * array( array( 'y') ) * ); * returns: - * array( + * array( * array( 'x', '2' ), * array( 'x' ), * array( 'y' ) @@ -2592,7 +2760,7 @@ function wfParseUrl( $url ) { $bits['delimiter'] = ':'; // parse_url detects for news: and mailto: the host part of an url as path // We have to correct this wrong detection - if ( isset ( $bits['path'] ) ) { + if ( isset( $bits['path'] ) ) { $bits['host'] = $bits['path']; $bits['path'] = ''; } @@ -2613,7 +2781,7 @@ function wfMakeUrlIndex( $url ) { // For emails reverse domainpart only if ( $bits['scheme'] == 'mailto' ) { $mailparts = explode( '@', $bits['host'], 2 ); - if ( count($mailparts) === 2 ) { + if ( count( $mailparts ) === 2 ) { $domainpart = strtolower( implode( '.', array_reverse( explode( '.', $mailparts[1] ) ) ) ); } else { // No domain specified, don't mangle it @@ -2632,32 +2800,55 @@ function wfMakeUrlIndex( $url ) { $prot = $bits['scheme']; $index = $prot . $bits['delimiter'] . $reversedHost; // Leave out user and password. Add the port, path, query and fragment - if ( isset( $bits['port'] ) ) $index .= ':' . $bits['port']; + if ( isset( $bits['port'] ) ) { + $index .= ':' . $bits['port']; + } if ( isset( $bits['path'] ) ) { $index .= $bits['path']; } else { $index .= '/'; } - if ( isset( $bits['query'] ) ) $index .= '?' . $bits['query']; - if ( isset( $bits['fragment'] ) ) $index .= '#' . $bits['fragment']; + if ( isset( $bits['query'] ) ) { + $index .= '?' . $bits['query']; + } + if ( isset( $bits['fragment'] ) ) { + $index .= '#' . $bits['fragment']; + } return $index; } /** * Do any deferred updates and clear the list - * TODO: This could be in Wiki.php if that class made any sense at all + * + * @param $commit String: set to 'commit' to commit after every update to + * prevent lock contention */ -function wfDoUpdates() -{ - global $wgPostCommitUpdateList, $wgDeferredUpdateList; - foreach ( $wgDeferredUpdateList as $update ) { - $update->doUpdate(); +function wfDoUpdates( $commit = '' ) { + global $wgDeferredUpdateList; + + wfProfileIn( __METHOD__ ); + + // No need to get master connections in case of empty updates array + if ( !count( $wgDeferredUpdateList ) ) { + wfProfileOut( __METHOD__ ); + return; + } + + $doCommit = $commit == 'commit'; + if ( $doCommit ) { + $dbw = wfGetDB( DB_MASTER ); } - foreach ( $wgPostCommitUpdateList as $update ) { + + foreach ( $wgDeferredUpdateList as $update ) { $update->doUpdate(); + + if ( $doCommit && $dbw->trxLevel() ) { + $dbw->commit(); + } } + $wgDeferredUpdateList = array(); - $wgPostCommitUpdateList = array(); + wfProfileOut( __METHOD__ ); } /** @@ -2674,7 +2865,7 @@ function wfDoUpdates() * @param $lowercase Boolean * @return String or false on invalid input */ -function wfBaseConvert( $input, $sourceBase, $destBase, $pad=1, $lowercase=true ) { +function wfBaseConvert( $input, $sourceBase, $destBase, $pad = 1, $lowercase = true ) { $input = strval( $input ); if( $sourceBase < 2 || $sourceBase > 36 || @@ -2688,7 +2879,7 @@ function wfBaseConvert( $input, $sourceBase, $destBase, $pad=1, $lowercase=true $input == '' ) { return false; } - $digitChars = ( $lowercase ) ? '0123456789abcdefghijklmnopqrstuvwxyz' : '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; + $digitChars = ( $lowercase ) ? '0123456789abcdefghijklmnopqrstuvwxyz' : '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ'; $inDigits = array(); $outChars = ''; @@ -2752,7 +2943,7 @@ function wfBaseConvert( $input, $sourceBase, $destBase, $pad=1, $lowercase=true * @param $name String * @param $p Array: parameters */ -function wfCreateObject( $name, $p ){ +function wfCreateObject( $name, $p ) { $p = array_values( $p ); switch ( count( $p ) ) { case 0: @@ -2770,14 +2961,15 @@ function wfCreateObject( $name, $p ){ case 6: return new $name( $p[0], $p[1], $p[2], $p[3], $p[4], $p[5] ); default: - throw new MWException( "Too many arguments to construtor in wfCreateObject" ); + throw new MWException( 'Too many arguments to construtor in wfCreateObject' ); } } function wfHttpOnlySafe() { global $wgHttpOnlyBlacklist; - if( !version_compare("5.2", PHP_VERSION, "<") ) + if( !version_compare( '5.2', PHP_VERSION, '<' ) ) { return false; + } if( isset( $_SERVER['HTTP_USER_AGENT'] ) ) { foreach( $wgHttpOnlyBlacklist as $regex ) { @@ -2793,15 +2985,15 @@ function wfHttpOnlySafe() { /** * Initialise php session */ -function wfSetupSession() { - global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain, +function wfSetupSession( $sessionId = false ) { + global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler; if( $wgSessionsInMemcached ) { require_once( 'MemcachedSessions.php' ); } 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 ); + ini_set( 'session.save_handler', $wgSessionHandler ); } $httpOnlySafe = wfHttpOnlySafe(); wfDebugLog( 'cookie', @@ -2819,6 +3011,9 @@ function wfSetupSession() { session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure ); } session_cache_limiter( 'private, must-revalidate' ); + if ( $sessionId ) { + session_id( $sessionId ); + } wfSuppressWarnings(); session_start(); wfRestoreWarnings(); @@ -2845,7 +3040,7 @@ function wfGetPrecompiledData( $name ) { function wfGetCaller( $level = 2 ) { $backtrace = wfDebugBacktrace(); if ( isset( $backtrace[$level] ) ) { - return wfFormatStackFrame($backtrace[$level]); + return wfFormatStackFrame( $backtrace[$level] ); } else { $caller = 'unknown'; } @@ -2871,10 +3066,10 @@ function wfGetAllCallers( $limit = 3 ) { /** * Return a string representation of frame */ -function wfFormatStackFrame($frame) { - return isset( $frame["class"] )? - $frame["class"]."::".$frame["function"]: - $frame["function"]; +function wfFormatStackFrame( $frame ) { + return isset( $frame['class'] ) ? + $frame['class'] . '::' . $frame['function'] : + $frame['function']; } /** @@ -2924,7 +3119,7 @@ function wfSplitWikiID( $wiki ) { return $bits; } -/* +/** * Get a Database object. * @param $db Integer: index of the connection to get. May be DB_MASTER for the * master (for write queries), DB_SLAVE for potentially lagged read @@ -2939,6 +3134,8 @@ function wfSplitWikiID( $wiki ) { * Note: multiple calls to wfGetDB(DB_SLAVE) during the course of one request * will always return the same object, unless the underlying connection or load * balancer is manually destroyed. + * + * @return DatabaseBase */ function &wfGetDB( $db, $groups = array(), $wiki = false ) { return wfGetLB( $wiki )->getConnection( $db, $groups, $wiki ); @@ -2964,7 +3161,7 @@ function &wfGetLBFactory() { /** * Find a file. * Shortcut for RepoGroup::singleton()->findFile() - * @param $title Either a string or Title object + * @param $title 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 @@ -2972,7 +3169,7 @@ function &wfGetLBFactory() { * * ignoreRedirect: If true, do not follow file redirects * - * private: If true, return restricted (deleted) files if the current + * private: If true, return restricted (deleted) files if the current * user is allowed to view them. Otherwise, such files will not * be found. * @@ -2987,7 +3184,7 @@ function wfFindFile( $title, $options = array() ) { /** * 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 + * @param $title Title or String * @return File, or null if passed an invalid Title */ function wfLocalFile( $title ) { @@ -3018,12 +3215,13 @@ function wfScript( $script = 'index' ) { global $wgScriptPath, $wgScriptExtension; return "{$wgScriptPath}/{$script}{$wgScriptExtension}"; } + /** - * Get the script url. + * Get the script URL. * - * @return script url + * @return script URL */ -function wfGetScriptUrl(){ +function wfGetScriptUrl() { if( isset( $_SERVER['SCRIPT_NAME'] ) ) { # # as it was called, minus the query string. @@ -3054,9 +3252,10 @@ function wfBoolToStr( $value ) { /** * Load an extension messages file - * @deprecated in 1.16 (warnings in 1.18, removed in ?) + * @deprecated in 1.16, warnings in 1.18, remove in 1.20 */ function wfLoadExtensionMessages( $extensionName, $langcode = false ) { + wfDeprecated( __FUNCTION__ ); } /** @@ -3116,18 +3315,21 @@ function wfDeprecated( $function ) { */ function wfWarn( $msg, $callerOffset = 1, $level = E_USER_NOTICE ) { $callers = wfDebugBacktrace(); - if( isset( $callers[$callerOffset+1] ) ){ - $callerfunc = $callers[$callerOffset+1]; + if( isset( $callers[$callerOffset + 1] ) ){ + $callerfunc = $callers[$callerOffset + 1]; $callerfile = $callers[$callerOffset]; - if( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ){ + if( isset( $callerfile['file'] ) && isset( $callerfile['line'] ) ) { $file = $callerfile['file'] . ' at line ' . $callerfile['line']; } else { $file = '(internal function)'; } $func = ''; - if( isset( $callerfunc['class'] ) ) + if( isset( $callerfunc['class'] ) ) { $func .= $callerfunc['class'] . '::'; - $func .= @$callerfunc['function']; + } + if( isset( $callerfunc['function'] ) ) { + $func .= $callerfunc['function']; + } $msg .= " [Called from $func in $file]"; } @@ -3158,12 +3360,14 @@ function wfWaitForSlaves( $maxLag, $wiki = false ) { $lb = wfGetLB( $wiki ); list( $host, $lag ) = $lb->getMaxLag( $wiki ); while( $lag > $maxLag ) { - $name = @gethostbyaddr( $host ); + wfSuppressWarnings(); + $name = gethostbyaddr( $host ); + wfRestoreWarnings(); if( $name !== false ) { $host = $name; } print "Waiting for $host (lagged $lag seconds)...\n"; - sleep($maxLag); + sleep( $maxLag ); list( $host, $lag ) = $lb->getMaxLag(); } } @@ -3174,7 +3378,6 @@ function wfWaitForSlaves( $maxLag, $wiki = false ) { * Do not use it in any other context, its behaviour is subject to change. */ function wfOut( $s ) { - static $lineStarted = false; global $wgCommandLineMode; if ( $wgCommandLineMode && !defined( 'MEDIAWIKI_INSTALL' ) ) { echo $s; @@ -3185,14 +3388,14 @@ function wfOut( $s ) { } /** - * Count down from $n to zero on the terminal, with a one-second pause + * 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 ) { @@ -3202,14 +3405,14 @@ function wfCountDown( $n ) { echo "\n"; } -/** Generate a random 32-character hexadecimal token. +/** + * Generate a random 32-character hexadecimal token. * @param $salt Mixed: some sort of salt, if necessary, to add to random * characters before hashing. */ function wfGenerateToken( $salt = '' ) { - $salt = serialize($salt); - - return md5( mt_rand( 0, 0x7fffffff ) . $salt ); + $salt = serialize( $salt ); + return md5( mt_rand( 0, 0x7fffffff ) . $salt ); } /** @@ -3219,7 +3422,13 @@ function wfGenerateToken( $salt = '' ) { function wfStripIllegalFilenameChars( $name ) { global $wgIllegalFileChars; $name = wfBaseName( $name ); - $name = preg_replace("/[^".Title::legalChars()."]".($wgIllegalFileChars ? "|[".$wgIllegalFileChars."]":"")."/",'-',$name); + $name = preg_replace( + "/[^" . Title::legalChars() . "]" . + ( $wgIllegalFileChars ? "|[" . $wgIllegalFileChars . "]" : '' ) . + "/", + '-', + $name + ); return $name; } @@ -3231,31 +3440,31 @@ function wfStripIllegalFilenameChars( $name ) { */ function wfArrayInsertAfter( $array, $insert, $after ) { // Find the offset of the element to insert after. - $keys = array_keys($array); + $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 ); - + $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 ) { + foreach ( get_object_vars( $object ) as $key => $value ) { + if ( is_object( $value ) && $recursive ) { $value = wfObjectToArray( $value ); } - + $array[$key] = $value; } - + return $array; } @@ -3263,22 +3472,21 @@ function wfObjectToArray( $object, $recursive = true ) { * Set PHP's memory limit to the larger of php.ini or $wgMemoryLimit; * @return Integer value memory was set to. */ - -function wfMemoryLimit () { +function wfMemoryLimit() { global $wgMemoryLimit; - $memlimit = wfShorthandToInteger( ini_get( "memory_limit" ) ); - $conflimit = wfShorthandToInteger( $wgMemoryLimit ); + $memlimit = wfShorthandToInteger( ini_get( 'memory_limit' ) ); if( $memlimit != -1 ) { + $conflimit = wfShorthandToInteger( $wgMemoryLimit ); if( $conflimit == -1 ) { wfDebug( "Removing PHP's memory limit\n" ); wfSuppressWarnings(); - ini_set( "memory_limit", $conflimit ); + ini_set( 'memory_limit', $conflimit ); wfRestoreWarnings(); return $conflimit; } elseif ( $conflimit > $memlimit ) { wfDebug( "Raising PHP's memory limit to $conflimit bytes\n" ); wfSuppressWarnings(); - ini_set( "memory_limit", $conflimit ); + ini_set( 'memory_limit', $conflimit ); wfRestoreWarnings(); return $conflimit; } @@ -3291,24 +3499,32 @@ function wfMemoryLimit () { * @param $string String * @return Integer */ -function wfShorthandToInteger ( $string = '' ) { - $string = trim($string); - if( empty($string) ) { return -1; } - $last = strtolower($string[strlen($string)-1]); - $val = intval($string); - switch($last) { +function wfShorthandToInteger( $string = '' ) { + $string = trim( $string ); + if( $string === '' ) { + return -1; + } + $last = $string[strlen( $string ) - 1]; + $val = intval( $string ); + switch( $last ) { case 'g': + case 'G': $val *= 1024; + // break intentionally missing case 'm': + case 'M': $val *= 1024; + // break intentionally missing case 'k': + case 'K': $val *= 1024; } return $val; } -/* Get the normalised IETF language tag +/** + * Get the normalised IETF language tag * @param $code String: The language code. * @return $langCode String: The language code which complying with BCP 47 standards. */ @@ -3317,20 +3533,21 @@ function wfBCP47( $code ) { foreach ( $codeSegment as $segNo => $seg ) { if ( count( $codeSegment ) > 0 ) { // ISO 3166 country code - if ( ( strlen( $seg ) == 2 ) && ( $segNo > 0 ) ) + if ( ( strlen( $seg ) == 2 ) && ( $segNo > 0 ) ) { $codeBCP[$segNo] = strtoupper( $seg ); // ISO 15924 script code - else if ( ( strlen( $seg ) == 4 ) && ( $segNo > 0 ) ) + } elseif ( ( strlen( $seg ) == 4 ) && ( $segNo > 0 ) ) { $codeBCP[$segNo] = ucfirst( $seg ); // Use lowercase for other cases - else + } else { $codeBCP[$segNo] = strtolower( $seg ); + } } else { // Use lowercase for single segment $codeBCP[$segNo] = strtolower( $seg ); } } - $langCode = implode ( '-' , $codeBCP ); + $langCode = implode( '-', $codeBCP ); return $langCode; }