<?php
/**
- * See user.doc
+ * See user.txt
*
* @package MediaWiki
*/
$fname = 'User::loadDefaults' . $n;
wfProfileIn( $fname );
- global $wgContLang, $wgIP;
+ global $wgContLang, $wgIP, $wgDBname;
global $wgNamespacesToBeSearchedDefault;
$this->mId = 0;
unset( $this->mSkin );
$this->mDataLoaded = false;
$this->mBlockedby = -1; # Unset
- $this->mTouched = '0'; # Allow any pages to be cached
$this->setToken(); # Random
$this->mHash = false;
+
+ if ( isset( $_COOKIE[$wgDBname.'LoggedOut'] ) ) {
+ $this->mTouched = wfTimestamp( TS_MW, $_COOKIE[$wgDBname.'LoggedOut'] );
+ }
+ else {
+ $this->mTouched = '0'; # Allow any pages to be cached
+ }
+
wfProfileOut( $fname );
}
/**
* Get blocking information
* @access private
+ * @param bool $bFromSlave Specify whether to check slave or master. To improve performance,
+ * non-critical checks are done against slaves. Check when actually saving should be done against
+ * master.
+ *
+ * Note that even if $bFromSlave is false, the check is done first against slave, then master.
+ * The logic is that if blocked on slave, we'll assume it's either blocked on master or
+ * just slightly outta sync and soon corrected - safer to block slightly more that less.
+ * And it's cheaper to check slave first, then master if needed, than master always.
*/
function getBlockedStatus() {
- global $wgIP, $wgBlockCache, $wgProxyList;
+ global $wgIP, $wgBlockCache, $wgProxyList, $wgEnableSorbs, $bFromSlave;
if ( -1 != $this->mBlockedby ) { return; }
# User blocking
if ( $this->mId ) {
$block = new Block();
- if ( $block->load( $wgIP , $this->mId ) ) {
+ $block->forUpdate( $bFromSlave );
+ if ( $block->load( $wgIP , $this->mId ) ) {
$this->mBlockedby = $block->mBy;
$this->mBlockreason = $block->mReason;
+ $this->spreadBlock();
}
}
# IP/range blocking
if ( !$this->mBlockedby ) {
- $block = $wgBlockCache->get( $wgIP );
+ # Check first against slave, and optionally from master.
+ $block = $wgBlockCache->get( $wgIP, true );
+ if ( !$block && !$bFromSlave )
+ {
+ # Not blocked: check against master, to make sure.
+ $wgBlockCache->clearLocal( );
+ $block = $wgBlockCache->get( $wgIP, false );
+ }
if ( $block !== false ) {
$this->mBlockedby = $block->mBy;
$this->mBlockreason = $block->mReason;
# Proxy blocking
if ( !$this->mBlockedby ) {
if ( array_key_exists( $wgIP, $wgProxyList ) ) {
+ $this->mBlockedby = wfMsg( 'proxyblocker' );
$this->mBlockreason = wfMsg( 'proxyblockreason' );
- $this->mBlockedby = "Proxy blocker";
}
}
+
+ # DNSBL
+ if ( !$this->mBlockedby && $wgEnableSorbs ) {
+ if ( $this->inSorbsBlacklist( $wgIP ) ) {
+ $this->mBlockedby = wfMsg( 'sorbs' );
+ $this->mBlockreason = wfMsg( 'sorbsreason' );
+ }
+ }
+
}
+ function inSorbsBlacklist( $ip ) {
+ $fname = 'User::inSorbsBlacklist';
+ wfProfileIn( $fname );
+
+ $found = false;
+ $host = '';
+
+ if ( preg_match( '/^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/', $ip, $m ) ) {
+ # Make hostname
+ for ( $i=4; $i>=1; $i-- ) {
+ $host .= $m[$i] . '.';
+ }
+ $host .= 'http.dnsbl.sorbs.net.';
+
+ # Send query
+ $ipList = gethostbynamel( $host );
+
+ if ( $ipList ) {
+ wfDebug( "Hostname $host is {$ipList[0]}, it's a proxy!\n" );
+ $found = true;
+ } else {
+ wfDebug( "Requested $host, not found.\n" );
+ }
+ }
+
+ wfProfileOut( $fname );
+ return $found;
+ }
+
/**
* Check if user is blocked
* @return bool True if blocked, false otherwise
*/
- function isBlocked() {
- $this->getBlockedStatus();
+ function isBlocked( $bFromSlave = false ) {
+ $this->getBlockedStatus( $bFromSlave );
if ( 0 === $this->mBlockedby ) { return false; }
return true;
}
else
wfDebug( "User::loadFromSession() unable to save to memcached\n" );
}
- $user->spreadBlock();
return $user;
}
return new User(); # Can't log in from session
function loadFromDatabase() {
global $wgCommandLineMode, $wgAnonGroupId, $wgLoggedInGroupId;
$fname = "User::loadFromDatabase";
- if ( $this->mDataLoaded || $wgCommandLineMode ) {
+
+ # Counter-intuitive, breaks various things, use User::setLoaded() if you want to suppress
+ # loading in a command line script, don't assume all command line scripts need it like this
+ #if ( $this->mDataLoaded || $wgCommandLineMode ) {
+ if ( $this->mDataLoaded ) {
return;
}
# Set the random token (used for persistent authentication)
function setToken( $token = false ) {
+ global $wgSecretKey, $wgProxyKey, $wgDBname;
if ( !$token ) {
- $this->mToken = '';
- # Take random data from PRNG
- # This is reasonably secure if the PRNG has been seeded correctly
- for ($i = 0; $i<USER_TOKEN_LENGTH / 4; $i++) {
- $this->mToken .= sprintf( "%04X", mt_rand( 0, 65535 ) );
+ if ( $wgSecretKey ) {
+ $key = $wgSecretKey;
+ } elseif ( $wgProxyKey ) {
+ $key = $wgProxyKey;
+ } else {
+ $key = microtime();
}
+ $this->mToken = md5( $wgSecretKey . mt_rand( 0, 0x7fffffff ) . $wgDBname . $this->mId );
} else {
$this->mToken = $token;
}
$this->invalidateCache();
}
+ /**
+ * A more legible check for non-anonymousness.
+ * Returns true if the user is not an anonymous visitor.
+ *
+ * @return bool
+ */
+ function isLoggedIn() {
+ return( $this->getID() != 0 );
+ }
+
+ /**
+ * A more legible check for anonymousness.
+ * Returns true if the user is an anonymous visitor.
+ *
+ * @return bool
+ */
+ function isAnon() {
+ return !$this->isLoggedIn();
+ }
+
/**
* Check if a user is sysop
* Die with backtrace. Use User:isAllowed() instead.
* @deprecated
*/
function isSysop() {
- /**
- $this->loadFromDatabase();
- if ( 0 == $this->mId ) { return false; }
-
- return in_array( 'sysop', $this->mRights );
- */
- wfDebugDieBacktrace("User::isSysop() is deprecated. Use User::isAllowed() instead");
+ wfDebugDieBacktrace("User::isSysop() is deprecated. Use User::isAllowed() instead");
}
/** @deprecated */
function isDeveloper() {
- /**
- $this->loadFromDatabase();
- if ( 0 == $this->mId ) { return false; }
-
- return in_array( 'developer', $this->mRights );
- */
- wfDebugDieBacktrace("User::isDeveloper() is deprecated. Use User::isAllowed() instead");
+ wfDebugDieBacktrace("User::isDeveloper() is deprecated. Use User::isAllowed() instead");
}
/** @deprecated */
function isBureaucrat() {
- /**
- $this->loadFromDatabase();
- if ( 0 == $this->mId ) { return false; }
-
- return in_array( 'bureaucrat', $this->mRights );
- */
- wfDebugDieBacktrace("User::isBureaucrat() is deprecated. Use User::isAllowed() instead");
+ wfDebugDieBacktrace("User::isBureaucrat() is deprecated. Use User::isAllowed() instead");
}
/**
$dbw =& wfGetDB( DB_MASTER );
$success = $dbw->update( 'watchlist',
array( /* SET */
- 'wl_notificationtimestamp' => $dbw->timestamp(0)
+ 'wl_notificationtimestamp' => 0
), array( /* WHERE */
'wl_title' => $title->getDBkey(),
'wl_namespace' => $title->getNamespace(),
setcookie( $wgDBname.'UserID', '', time() - 3600, $wgCookiePath, $wgCookieDomain );
setcookie( $wgDBname.'Token', '', time() - 3600, $wgCookiePath, $wgCookieDomain );
+
+ # Remember when user logged out, to prevent seeing cached pages
+ setcookie( $wgDBname.'LoggedOut', wfTimestampNow(), time() + 86400, $wgCookiePath, $wgCookieDomain );
}
/**
// it will always be 0 when this function is called by parsercache.
$confstr = $this->getOption( 'math' );
- $confstr .= '!' . $this->getOption( 'highlightbroken' );
$confstr .= '!' . $this->getOption( 'stubthreshold' );
$confstr .= '!' . $this->getOption( 'editsection' );
- $confstr .= '!' . $this->getOption( 'editsectiononrightclick' );
- $confstr .= '!' . $this->getOption( 'showtoc' );
$confstr .= '!' . $this->getOption( 'date' );
$confstr .= '!' . $this->getOption( 'numberheadings' );
$confstr .= '!' . $this->getOption( 'language' );
+ $confstr .= '!' . $this->getOption( 'thumbsize' );
// add in language specific options, if any
$extra = $wgContLang->getExtraHashOptions();
$confstr .= $extra;
return wfSetVar( $this->mDataLoaded, $loaded );
}
+ /**
+ * Get this user's personal page title.
+ *
+ * @return Title
+ * @access public
+ */
function getUserPage() {
return Title::makeTitle( NS_USER, $this->mName );
}
+
+ /**
+ * Get this user's talk page title.
+ *
+ * @return Title
+ * @access public
+ */
+ function getTalkPage() {
+ $title = $this->getUserPage();
+ return $title->getTalkPage();
+ }
/**
* @static
}
return false;
}
+
+ /**
+ * Initialize (if necessary) and return a session token value
+ * which can be used in edit forms to show that the user's
+ * login credentials aren't being hijacked with a foreign form
+ * submission.
+ *
+ * @param mixed $salt - Optional function-specific data for hash.
+ * Use a string or an array of strings.
+ * @return string
+ * @access public
+ */
+ function editToken( $salt = '' ) {
+ if( !isset( $_SESSION['wsEditToken'] ) ) {
+ $token = dechex( mt_rand() ) . dechex( mt_rand() );
+ $_SESSION['wsEditToken'] = $token;
+ } else {
+ $token = $_SESSION['wsEditToken'];
+ }
+ if( is_array( $salt ) ) {
+ $salt = implode( '|', $salt );
+ }
+ return md5( $token . $salt );
+ }
+
+ /**
+ * Check given value against the token value stored in the session.
+ * A match should confirm that the form was submitted from the
+ * user's own login session, not a form submission from a third-party
+ * site.
+ *
+ * @param string $val - the input value to compare
+ * @param string $salt - Optional function-specific data for hash
+ * @return bool
+ * @access public
+ */
+ function matchEditToken( $val, $salt = '' ) {
+ return ( $val == $this->editToken( $salt ) );
+ }
}
?>