die( "This file is part of MediaWiki, it is not a valid entry point" );
}
-require_once dirname( __FILE__ ) . '/normal/UtfNormalUtil.php';
+if ( !defined( 'MW_COMPILED' ) ) {
+ require_once( dirname( __FILE__ ) . '/normal/UtfNormalUtil.php' );
+}
// Hide compatibility functions from Doxygen
/// @cond
/**
* Compatibility functions
*
- * We support PHP 5.1.x and up.
+ * We support PHP 5.2.3 and up.
* Re-implementations of newer functions or functions in non-standard
* PHP extensions may be included here.
*/
$exists = file_exists( $file );
$size = $exists ? filesize( $file ) : false;
if ( !$exists || ( $size !== false && $size + strlen( $text ) < 0x7fffffff ) ) {
- error_log( $text, 3, $file );
+ file_put_contents( $file, $text, FILE_APPEND );
}
wfRestoreWarnings();
}
*/
function wfLogProfilingData() {
global $wgRequestTime, $wgDebugLogFile, $wgDebugRawPage, $wgRequest;
- global $wgProfiler, $wgProfileLimit, $wgUser;
+ global $wgProfileLimit, $wgUser;
+
+ $profiler = Profiler::instance();
+
# Profiling must actually be enabled...
- if( is_null( $wgProfiler ) ) {
+ if ( $profiler->isStub() ) {
return;
}
- # Get total page request time
+
+ // Get total page request time and only show pages that longer than
+ // $wgProfileLimit time (default is 0)
$now = wfTime();
$elapsed = $now - $wgRequestTime;
- # Only show pages that longer than $wgProfileLimit time (default is 0)
- if( $elapsed <= $wgProfileLimit ) {
+ if ( $elapsed <= $wgProfileLimit ) {
return;
}
- $prof = wfGetProfilingOutput( $wgRequestTime, $elapsed );
+
+ $profiler->logData();
+
+ // Check whether this should be logged in the debug file.
+ if ( $wgDebugLogFile == '' || ( $wgRequest->getVal( 'action' ) == 'raw' && !$wgDebugRawPage ) ) {
+ return;
+ }
+
$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
// FIXME: We can detect some anons even if it is not loaded. See User::getId()
- if( $wgUser->mDataLoaded && $wgUser->isAnon() ) {
+ 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 ) ) {
- wfErrorLog( $log . $prof, $wgDebugLogFile );
- }
+
+ wfErrorLog( $log . $profiler->getOutput(), $wgDebugLogFile );
}
/**
* The intention is that this function replaces all old wfMsg* functions.
* @param $key \string Message key.
* Varargs: normal message parameters.
- * @return \type{Message}
+ * @return Message
* @since 1.17
*/
function wfMessage( $key /*...*/) {
* for the first message which is non-empty. If all messages are empty then an
* instance of the first message key is returned.
* Varargs: message keys
- * @return \type{Message}
+ * @return Message
* @since 1.18
*/
function wfMessageFallback( /*...*/ ) {
$args = func_get_args();
- return call_user_func_array( array( 'Message', 'newFallbackSequence' ), $args );
+ return MWFunction::callArray( 'Message::newFallbackSequence', $args );
}
/**
/**
* Get a message from the language file, for the content
+ *
+ * @deprecated in 1.18; use wfMessage()
*/
function wfMsgNoDBForContent( $key ) {
+ wfDeprecated( __FUNCTION__ );
global $wgForceUIMsgAsContentMsg;
$args = func_get_args();
array_shift( $args );
* @param $key String
*/
function wfMsgWeirdKey( $key ) {
+ wfDeprecated( __FUNCTION__ );
$source = wfMsgGetKey( $key, false, true, false );
- if ( wfEmptyMsg( $key, $source ) ) {
+ if ( wfEmptyMsg( $key ) ) {
return '';
} else {
return $source;
* @return string
*/
function wfMsgWikiHtml( $key ) {
- global $wgOut;
$args = func_get_args();
array_shift( $args );
- return wfMsgReplaceArgs( $wgOut->parse( wfMsgGetKey( $key, true ), /* can't be set to false */ true ), $args );
+ return wfMsgReplaceArgs(
+ MessageCache::singleton()->parse( wfMsgGetKey( $key, true ), $key, /* can't be set to false */ true )->getText(),
+ $args );
}
/**
* Behavior for conflicting options (e.g., parse+parseinline) is undefined.
*/
function wfMsgExt( $key, $options ) {
- global $wgOut;
-
$args = func_get_args();
array_shift( $args );
array_shift( $args );
$string = wfMsgReplaceArgs( $string, $args );
}
+ $messageCache = MessageCache::singleton();
if( in_array( 'parse', $options, true ) ) {
- $string = $wgOut->parse( $string, true, !$forContent, $langCodeObj );
+ $string = $messageCache->parse( $string, $key, true, !$forContent, $langCodeObj )->getText();
} elseif ( in_array( 'parseinline', $options, true ) ) {
- $string = $wgOut->parse( $string, true, !$forContent, $langCodeObj );
+ $string = $messageCache->parse( $string, $key, true, !$forContent, $langCodeObj )->getText();
$m = array();
if( preg_match( '/^<p>(.*)\n?<\/p>\n?$/sU', $string, $m ) ) {
$string = $m[1];
}
} elseif ( in_array( 'parsemag', $options, true ) ) {
- $string = MessageCache::singleton()->transform( $string,
+ $string = $messageCache->transform( $string,
!$forContent, $langCodeObj );
}
}
/**
- * Print a simple message and die, returning nonzero to the shell if any.
- * Plain die() fails to return nonzero to the shell if you pass a string.
+ * Print an error message and die, returning nonzero to the shell if any. Plain die()
+ * fails to return nonzero to the shell if you pass a string. Entry points may customise
+ * this function to return a prettier error message, but implementations must not assume
+ * access to any of the usual MediaWiki infrastructure (AutoLoader, localisation, database,
+ * etc). This should not be called directly once $wgFullyInitialised is set; instead,
+ * throw an exception and let Exception.php handle whether or not it's possible to show
+ * a prettier error.
* @param $msg String
*/
-function wfDie( $msg = '' ) {
- echo $msg;
- die( 1 );
+if( !function_exists( 'wfDie' ) ){
+ function wfDie( $msg = '' ) {
+ echo $msg;
+ die( 1 );
+ }
}
/**
if( $status['name'] == 'ob_gzhandler' ) {
// Reset the 'Content-Encoding' field set by this handler
// so we can start fresh.
- header( 'Content-Encoding:' );
+ if ( function_exists( 'header_remove' ) ) {
+ // Available since PHP 5.3.0
+ header_remove( 'Content-Encoding' );
+ } else {
+ // We need to provide a valid content-coding. See bug 28069
+ header( 'Content-Encoding: identity' );
+ }
break;
}
}
}
} else {
if ( !$suppressCount ) {
- $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE ) );
+ // E_DEPRECATED is undefined in PHP 5.2
+ if( !defined( 'E_DEPRECATED' ) ){
+ define( 'E_DEPRECATED', 8192 );
+ }
+ $originalLevel = error_reporting( E_ALL & ~( E_WARNING | E_NOTICE | E_USER_WARNING | E_USER_NOTICE | E_DEPRECATED ) );
}
++$suppressCount;
}
return $isWindows;
}
+/**
+ * Check if we are running under HipHop
+ */
+function wfIsHipHop() {
+ return function_exists( 'hphp_thread_set_warmup_enabled' );
+}
+
/**
* Swap two variables
*/
/**
* Increment a statistics counter
*/
-function wfIncrStats( $key ) {
+function wfIncrStats( $key, $count = 1 ) {
global $wgStatsMethod;
+ $count = intval( $count );
+
if( $wgStatsMethod == 'udp' ) {
- global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgDBname;
+ global $wgUDPProfilerHost, $wgUDPProfilerPort, $wgDBname, $wgAggregateStatsID;
static $socket;
+
+ $id = $wgAggregateStatsID !== false ? $wgAggregateStatsID : $wgDBname;
+
if ( !$socket ) {
$socket = socket_create( AF_INET, SOCK_DGRAM, SOL_UDP );
- $statline = "stats/{$wgDBname} - 1 1 1 1 1 -total\n";
+ $statline = "stats/{$id} - {$count} 1 1 1 1 -total\n";
socket_sendto(
$socket,
$statline,
$wgUDPProfilerPort
);
}
- $statline = "stats/{$wgDBname} - 1 1 1 1 1 {$key}\n";
+ $statline = "stats/{$id} - {$count} 1 1 1 1 {$key}\n";
wfSuppressWarnings();
socket_sendto(
$socket,
} elseif( $wgStatsMethod == 'cache' ) {
global $wgMemc;
$key = wfMemcKey( 'stats', $key );
- if ( is_null( $wgMemc->incr( $key ) ) ) {
- $wgMemc->add( $key, 1 );
+ if ( is_null( $wgMemc->incr( $key, $count ) ) ) {
+ $wgMemc->add( $key, $count );
}
} else {
// Disabled
*
* @param $extension String A PHP extension. The file suffix (.so or .dll)
* should be omitted
+ * @param $fileName String Name of the library, if not $extension.suffix
* @return Bool - Whether or not the extension is loaded
*/
-function wfDl( $extension ) {
+function wfDl( $extension, $fileName = null ) {
if( extension_loaded( $extension ) ) {
return true;
}
- $canDl = ( function_exists( 'dl' ) && is_callable( 'dl' )
+ $canDl = false;
+ $sapi = php_sapi_name();
+ if( version_compare( PHP_VERSION, '5.3.0', '<' ) ||
+ $sapi == 'cli' || $sapi == 'cgi' || $sapi == 'embed' )
+ {
+ $canDl = ( function_exists( 'dl' ) && is_callable( 'dl' )
&& wfIniGetBool( 'enable_dl' ) && !wfIniGetBool( 'safe_mode' ) );
+ }
if( $canDl ) {
+ $fileName = $fileName ? $fileName : $extension;
+ if( wfIsWindows() ) {
+ $fileName = 'php_' . $fileName;
+ }
wfSuppressWarnings();
- dl( $extension . '.' . PHP_SHLIB_SUFFIX );
+ dl( $fileName . '.' . PHP_SHLIB_SUFFIX );
wfRestoreWarnings();
}
return extension_loaded( $extension );
// Decode and validate input string
$input = strtolower( $input );
for( $i = 0; $i < strlen( $input ); $i++ ) {
- $n = strpos( $digitChars, $input{$i} );
+ $n = strpos( $digitChars, $input[$i] );
if( $n === false || $n > $sourceBase ) {
return false;
}
function wfHttpOnlySafe() {
global $wgHttpOnlyBlacklist;
- if( !version_compare( '5.2', PHP_VERSION, '<' ) ) {
- return false;
- }
if( isset( $_SERVER['HTTP_USER_AGENT'] ) ) {
foreach( $wgHttpOnlyBlacklist as $regex ) {
global $wgSessionsInMemcached, $wgCookiePath, $wgCookieDomain,
$wgCookieSecure, $wgCookieHttpOnly, $wgSessionHandler;
if( $wgSessionsInMemcached ) {
- require_once( 'MemcachedSessions.php' );
+ if ( !defined( 'MW_COMPILED' ) ) {
+ require_once( 'MemcachedSessions.php' );
+ }
+ session_set_save_handler( 'memsess_open', 'memsess_close', 'memsess_read',
+ 'memsess_write', 'memsess_destroy', 'memsess_gc' );
+
+ // It's necessary to register a shutdown function to call session_write_close(),
+ // because by the time the request shutdown function for the session module is
+ // called, $wgMemc has already been destroyed. Shutdown functions registered
+ // this way are called before object destruction.
+ register_shutdown_function( 'memsess_write_close' );
} 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();
+ $httpOnlySafe = wfHttpOnlySafe() && $wgCookieHttpOnly;
wfDebugLog( 'cookie',
'session_set_cookie_params: "' . implode( '", "',
array(
$wgCookiePath,
$wgCookieDomain,
$wgCookieSecure,
- $httpOnlySafe && $wgCookieHttpOnly ) ) . '"' );
- if( $httpOnlySafe && $wgCookieHttpOnly ) {
- session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $wgCookieHttpOnly );
- } else {
- // PHP 5.1 throws warnings if you pass the HttpOnly parameter for 5.2.
- session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure );
- }
+ $httpOnlySafe ) ) . '"' );
+ session_set_cookie_params( 0, $wgCookiePath, $wgCookieDomain, $wgCookieSecure, $httpOnlySafe );
session_cache_limiter( 'private, must-revalidate' );
if ( $sessionId ) {
session_id( $sessionId );
: '/dev/null';
}
-/**
- * Displays a maxlag error
- *
- * @param $host String: server that lags the most
- * @param $lag Integer: maxlag (actual)
- * @param $maxLag Integer: maxlag (requested)
- */
-function wfMaxlagError( $host, $lag, $maxLag ) {
- global $wgShowHostnames;
- header( 'HTTP/1.1 503 Service Unavailable' );
- header( 'Retry-After: ' . max( intval( $maxLag ), 5 ) );
- header( 'X-Database-Lag: ' . intval( $lag ) );
- header( 'Content-Type: text/plain' );
- if( $wgShowHostnames ) {
- echo "Waiting for $host: $lag seconds lagged\n";
- } else {
- echo "Waiting for a database server: $lag seconds lagged\n";
- }
-}
-
/**
* Throws a warning that $function is deprecated
* @param $function String
}
/**
- * Sleep until the worst slave's replication lag is less than or equal to
- * $maxLag, in seconds. Use this when updating very large numbers of rows, as
+ * Modern version of wfWaitForSlaves(). Instead of looking at replication lag
+ * and waiting for it to go down, this waits for the slaves to catch up to the
+ * master position. Use this when updating very large numbers of rows, as
* in maintenance scripts, to avoid causing too much lag. Of course, this is
* a no-op if there are no slaves.
- *
- * Every time the function has to wait for a slave, it will print a message to
- * that effect (and then sleep for a little while), so it's probably not best
- * to use this outside maintenance scripts in its present form.
- *
- * @param $maxLag Integer
+ *
+ * @param $maxLag Integer (deprecated)
* @param $wiki mixed Wiki identifier accepted by wfGetLB
* @return null
*/
-function wfWaitForSlaves( $maxLag, $wiki = false ) {
- if( $maxLag ) {
- $lb = wfGetLB( $wiki );
- list( $host, $lag ) = $lb->getMaxLag( $wiki );
- while( $lag > $maxLag ) {
- wfSuppressWarnings();
- $name = gethostbyaddr( $host );
- wfRestoreWarnings();
- if( $name !== false ) {
- $host = $name;
- }
- print "Waiting for $host (lagged $lag seconds)...\n";
- sleep( $maxLag );
- list( $host, $lag ) = $lb->getMaxLag();
- }
+function wfWaitForSlaves( $maxLag = false, $wiki = false ) {
+ $lb = wfGetLB( $wiki );
+ // bug 27975 - Don't try to wait for slaves if there are none
+ // Prevents permission error when getting master position
+ if ( $lb->getServerCount() > 1 ) {
+ $dbw = $lb->getConnection( DB_MASTER );
+ $pos = $dbw->getMasterPos();
+ $lb->waitForAll( $pos );
}
}
* @param $array Array: The array.
* @param $insert Array: The array to insert.
* @param $after Mixed: The key to insert after
+ * @return Array
+ * @since 1.16
*/
function wfArrayInsertAfter( $array, $insert, $after ) {
// Find the offset of the element to insert after.
}
/* Recursively converts the parameter (an object) to an array with the same data */
-function wfObjectToArray( $object, $recursive = true ) {
+function wfObjectToArray( $objOrArray, $recursive = true ) {
$array = array();
- foreach ( get_object_vars( $object ) as $key => $value ) {
- if ( is_object( $value ) && $recursive ) {
+ if( is_object( $objOrArray ) ) {
+ $objOrArray = get_object_vars( $objOrArray );
+ }
+ foreach ( $objOrArray as $key => $value ) {
+ if ( $recursive && ( is_object( $value ) || is_array( $value ) ) ) {
$value = wfObjectToArray( $value );
}
}
return $ret;
}
+
+
+/**
+ * Get a cache object.
+ * @param integer $inputType Cache type, one the the CACHE_* constants.
+ *
+ * @return BagOStuff
+ */
+function wfGetCache( $inputType ) {
+ return ObjectCache::getInstance( $inputType );
+}
+
+/** Get the main cache object */
+function wfGetMainCache() {
+ global $wgMainCacheType;
+ return ObjectCache::getInstance( $wgMainCacheType );
+}
+
+/** Get the cache object used by the message cache */
+function wfGetMessageCacheStorage() {
+ global $wgMessageCacheType;
+ return ObjectCache::getInstance( $wgMessageCacheType );
+}
+
+/** Get the cache object used by the parser cache */
+function wfGetParserCacheStorage() {
+ global $wgParserCacheType;
+ return ObjectCache::getInstance( $wgParserCacheType );
+}
+