Version 4.3.0
This commit is contained in:
1 parent
96997ddd8e
commit
fe1acf984a
1349 files changed
+116159
-67711
No files matched your search
@@ -0,0 +1,297 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Database Session Handler
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 6 September 2017
|
||||
*/
|
||||
|
||||
namespace IPS\Session\Store;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Database Session Handler
|
||||
*/
|
||||
class _Database extends \IPS\Session\Store
|
||||
{
|
||||
/**
|
||||
* Load the session from the storage engine
|
||||
*
|
||||
* @param string $sessionId Session ID
|
||||
* @return array
|
||||
*/
|
||||
public function loadSession( $sessionId )
|
||||
{
|
||||
$session = NULL;
|
||||
/* Get from the database */
|
||||
try
|
||||
{
|
||||
/* If it looks like we're logged in, join the member row to save a query later */
|
||||
if ( \IPS\Session\Front::loggedIn() )
|
||||
{
|
||||
$session = \IPS\Db::i()->select( '*', 'core_sessions', array( 'id=?', $sessionId ), NULL, NULL, NULL, NULL, \IPS\Db::SELECT_MULTIDIMENSIONAL_JOINS )->join( 'core_members', 'core_members.member_id=core_sessions.member_id' )->first();
|
||||
if ( $session['core_members']['member_id'] )
|
||||
{
|
||||
\IPS\Member::constructFromData( $session['core_members'], FALSE );
|
||||
}
|
||||
$session = $session['core_sessions'];
|
||||
}
|
||||
/* If we're not logged in, just look at the session */
|
||||
else
|
||||
{
|
||||
$userAgent = \IPS\Http\Useragent::parse();
|
||||
|
||||
/* Spiders match by IP and useragent */
|
||||
if ( $userAgent->spider )
|
||||
{
|
||||
$session = \IPS\Db::i()->select( '*', 'core_sessions', array( 'id=? OR ( ip_address=? AND browser=? )', $sessionId, \IPS\Request::i()->ipAddress(), $_SERVER['HTTP_USER_AGENT'] ) )->first();
|
||||
}
|
||||
/* Normal users don't */
|
||||
else
|
||||
{
|
||||
$session = \IPS\Db::i()->select( '*', 'core_sessions', array( 'id=?', $sessionId ) )->first();
|
||||
}
|
||||
}
|
||||
}
|
||||
catch ( \UnderflowException $e ) { }
|
||||
|
||||
return $session;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the session storage engine
|
||||
*
|
||||
* @param string $data Session Data
|
||||
* @return void
|
||||
*/
|
||||
public function updateSession( $data )
|
||||
{
|
||||
\IPS\Db::i()->replace( 'core_sessions', $data, TRUE );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete from the session engine
|
||||
*
|
||||
* @param string $sessionId Session ID
|
||||
* @return void
|
||||
*/
|
||||
public function deleteSession( $sessionId )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_sessions', array( 'id=?', $sessionId ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete from the session engine
|
||||
*
|
||||
* @param int $memberId You can probably figure this out right?
|
||||
* @param string|NULL $userAgent User Agent [optional]
|
||||
* @param array|NULL $keepSessionIds Array of session ids to keep [optional]
|
||||
* @return void
|
||||
*/
|
||||
public function deleteByMember( $memberId, $userAgent=NULL, $keepSessionIds=NULL )
|
||||
{
|
||||
$where = array( array( 'member_id=?', $memberId ) );
|
||||
|
||||
if ( $userAgent )
|
||||
{
|
||||
$where[] = array( 'browser=?', $userAgent );
|
||||
}
|
||||
|
||||
if ( $keepSessionIds )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( 'id', $keepSessionIds, TRUE ) );
|
||||
}
|
||||
|
||||
\IPS\Db::i()->delete( 'core_sessions', $where );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete from the session engine
|
||||
*
|
||||
* @param int $memberId You can probably figure this out right?
|
||||
* @return array|FALSE
|
||||
*/
|
||||
public function getLatestMemberSession( $memberId )
|
||||
{
|
||||
try
|
||||
{
|
||||
return \IPS\Db::i()->select( '*', 'core_sessions', array( 'member_id=?', $memberId ), 'running_time DESC' )->first();
|
||||
}
|
||||
catch ( \UnderflowException $e )
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all active session keys
|
||||
*
|
||||
* @return array or session IDs
|
||||
*/
|
||||
public function getSessionIds()
|
||||
{
|
||||
return iterator_to_array( \IPS\Db::i()->select( 'id', 'core_sessions' ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear sessions - abstracted so it can be called externally without initiating a session
|
||||
*
|
||||
* @param int $timeout Sessions older than the number of seconds provided will be deleted
|
||||
* @return void
|
||||
*/
|
||||
public static function clearSessions( $timeout )
|
||||
{
|
||||
\IPS\Db::i()->delete( 'core_sessions', array( 'running_time<?', ( time() - $timeout ) ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all online users (but not spiders)
|
||||
*
|
||||
* @param int $flags Bitwise flags
|
||||
* @param array $skipGroups Ignore members in these groups
|
||||
* @param array|NULL $limit Limit [ offset, limit ]
|
||||
* @param int $memberGroup Limit by a specific member group ID
|
||||
* @param boolean $showAnonymous Show anonymously logged in peoples?
|
||||
* @param boolean $includeAllGroups Include all groups? Used for statistics primarily.
|
||||
* @return array
|
||||
*/
|
||||
public function getOnlineUsers( $flags=0, $sort='desc', $limit=NULL, $memberGroup=NULL, $showAnonymous=FALSE, $includeAllGroups=FALSE )
|
||||
{
|
||||
/* Query */
|
||||
$where = array(
|
||||
array( 's.running_time>?', \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ),
|
||||
array( "s.login_type!=?", \IPS\Session\Front::LOGIN_TYPE_SPIDER )
|
||||
);
|
||||
|
||||
if ( ! $showAnonymous )
|
||||
{
|
||||
$where[] = array( "s.login_type!=?", \IPS\Session\Front::LOGIN_TYPE_ANONYMOUS );
|
||||
}
|
||||
|
||||
if( ! $includeAllGroups )
|
||||
{
|
||||
$notInMyName = array();
|
||||
foreach( \IPS\Member\Group::groups() as $group )
|
||||
{
|
||||
if ( $group->g_hide_online_list )
|
||||
{
|
||||
$notInMyName[] = $group->g_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $notInMyName ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( 's.member_group', $notInMyName, TRUE ) );
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! $flags and ! $limit )
|
||||
{
|
||||
/* Simple query for PHP processing */
|
||||
return iterator_to_array( \IPS\Db::i()->select( 's.id,s.member_id,s.member_name,s.seo_name,s.member_group,s.login_type', array( 'core_sessions', 's' ), $where, 's.running_time ' . $sort )->setKeyField('id') );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* Complex group by mode with all the lovely trimmings yum */
|
||||
$subWhere = $where;
|
||||
|
||||
/* Ok, this looks odd, but the ONLY_FULL_GROUP_BY bites us here, so selecting max(id) allows us to return a session ID even though we're grouping on member_id */
|
||||
$where = array( array( "( core_sessions.id IN(?) OR ( core_sessions.member_id IS NULL AND core_sessions.login_type != ? AND core_sessions.running_time > ?) )", \IPS\Db::i()->select( 'MAX(id)', array( 'core_sessions', 's' ), $subWhere, NULL, NULL, 'member_id' ), \IPS\Session\Front::LOGIN_TYPE_SPIDER, \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ) );
|
||||
|
||||
if( ! $includeAllGroups )
|
||||
{
|
||||
if ( count( $notInMyName ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( 'core_sessions.member_group', $notInMyName, TRUE ) );
|
||||
}
|
||||
}
|
||||
|
||||
/* Limiting to a user group? */
|
||||
if ( $memberGroup )
|
||||
{
|
||||
$where[] = array( 'core_sessions.member_group=?', $memberGroup );
|
||||
}
|
||||
|
||||
/* Just looking for guests? */
|
||||
if ( $flags AND ! ( $flags & static::ONLINE_MEMBERS ) )
|
||||
{
|
||||
$where[] = array( '( core_sessions.member_id IS NULL )' );
|
||||
}
|
||||
|
||||
if ( $flags AND ! ( $flags & static::ONLINE_GUESTS ) )
|
||||
{
|
||||
/* No guests */
|
||||
$where[] = array( 'core_sessions.member_id IS NOT NULL' );
|
||||
}
|
||||
|
||||
/* Just fetching a count? */
|
||||
if ( $flags & static::ONLINE_COUNT_ONLY )
|
||||
{
|
||||
return \IPS\Db::i()->select( 'COUNT(*)', 'core_sessions', $where )->first();
|
||||
}
|
||||
|
||||
return iterator_to_array( \IPS\Db::i()->select( '*', 'core_sessions', $where, 'core_sessions.running_time ' . $sort, $limit )->setKeyField('id') );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all members active at a specific location
|
||||
*
|
||||
* @param string $app Application directory (core, forums, etc)
|
||||
* @param string $module Module
|
||||
* @param string $controller Controller
|
||||
* @param int $id Current item ID (empty if none)
|
||||
* @param string $url Current viewing URL
|
||||
* @return array
|
||||
*/
|
||||
public function getOnlineMembersByLocation( $app, $module, $controller, $id, $url )
|
||||
{
|
||||
$members = array();
|
||||
$where = array(
|
||||
array( 'core_sessions.login_type=' . \IPS\Session\Front::LOGIN_TYPE_MEMBER ),
|
||||
array( 'core_sessions.current_appcomponent=?', $app ),
|
||||
array( 'core_sessions.current_module=?', $module ),
|
||||
array( 'core_sessions.current_controller=?', $controller ),
|
||||
array( 'core_sessions.running_time>' . \IPS\DateTime::create()->sub( new \DateInterval( 'PT30M' ) )->getTimeStamp() ),
|
||||
array( 'core_sessions.location_url IS NOT NULL AND location_url LIKE ?', "{$url}%" ),
|
||||
array( 'core_sessions.member_id IS NOT NULL' )
|
||||
);
|
||||
|
||||
if( $id )
|
||||
{
|
||||
$where[] = array( 'core_sessions.current_id = ?', \IPS\Request::i()->id );
|
||||
}
|
||||
|
||||
$notInMyName = array();
|
||||
foreach( \IPS\Member\Group::groups() as $group )
|
||||
{
|
||||
if ( $group->g_hide_online_list )
|
||||
{
|
||||
$notInMyName[] = $group->g_id;
|
||||
}
|
||||
}
|
||||
|
||||
if ( count( $notInMyName ) )
|
||||
{
|
||||
$where[] = array( \IPS\Db::i()->in( 'core_sessions.member_group', $notInMyName, TRUE ) );
|
||||
}
|
||||
|
||||
foreach( \IPS\Db::i()->select( 'core_sessions.member_id,core_sessions.member_name,core_sessions.seo_name,core_sessions.member_group,core_sessions.login_type,core_sessions.in_editor', 'core_sessions', $where, 'core_sessions.running_time DESC' ) as $row )
|
||||
{
|
||||
if( $row['login_type'] == \IPS\Session\Front::LOGIN_TYPE_MEMBER and $row['member_name'] )
|
||||
{
|
||||
$members[ $row['member_id'] ] = $row;
|
||||
}
|
||||
}
|
||||
|
||||
return $members;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,393 @@
|
||||
<?php
|
||||
/**
|
||||
* @brief Redis Session Handler
|
||||
* @author <a href='https://www.invisioncommunity.com'>Invision Power Services, Inc.</a>
|
||||
* @copyright (c) Invision Power Services, Inc.
|
||||
* @license https://www.invisioncommunity.com/legal/standards/
|
||||
* @package Invision Community
|
||||
* @since 6 September 2017
|
||||
*/
|
||||
|
||||
namespace IPS\Session\Store;
|
||||
|
||||
/* To prevent PHP errors (extending class does not exist) revealing path */
|
||||
if ( !defined( '\IPS\SUITE_UNIQUE_KEY' ) )
|
||||
{
|
||||
header( ( isset( $_SERVER['SERVER_PROTOCOL'] ) ? $_SERVER['SERVER_PROTOCOL'] : 'HTTP/1.0' ) . ' 403 Forbidden' );
|
||||
exit;
|
||||
}
|
||||
|
||||
/**
|
||||
* Redis Session Handler
|
||||
*/
|
||||
class _Redis extends \IPS\Session\Store
|
||||
{
|
||||
/**
|
||||
* @brief Default expiration for keys in seconds
|
||||
*/
|
||||
static protected $ttl = 1800; #30 mins
|
||||
|
||||
/**
|
||||
* Load the session from the storage engine
|
||||
*
|
||||
* @param string $sessionId Session ID
|
||||
* @return array
|
||||
*/
|
||||
public function loadSession( $sessionId )
|
||||
{
|
||||
if ( $result = \IPS\Redis::i()->hGetAll( $this->_key( 'session_id_' . md5( $sessionId . \IPS\Settings::i()->sql_pass ) ) ) )
|
||||
{
|
||||
return \IPS\Redis::i()->decode( $result['data'] );
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update the session storage engine
|
||||
*
|
||||
* @param array $data Session data to store
|
||||
* @return void
|
||||
*/
|
||||
public function updateSession( $data )
|
||||
{
|
||||
/* Groups are loaded into memory so this does not cause a query */
|
||||
$group = \IPS\Member\Group::load( $data['member_group'] );
|
||||
|
||||
/* Update the specific session */
|
||||
\IPS\Redis::i()->delete( $this->_key( 'session_id_' . md5( $data['id'] . \IPS\Settings::i()->sql_pass ) ) );
|
||||
\IPS\Redis::i()->hMSet( $this->_key( 'session_id_' . md5( $data['id'] . \IPS\Settings::i()->sql_pass ) ), array(
|
||||
'member_id' => $data['member_id'],
|
||||
'member_name' => $data['member_name'],
|
||||
'seo_name' => $data['seo_name'],
|
||||
'member_group' => $data['member_group'],
|
||||
'login_type' => $data['login_type'],
|
||||
'in_editor' => $data['in_editor'],
|
||||
'data' => \IPS\Redis::i()->encode( $data )
|
||||
), static::$ttl );
|
||||
|
||||
/* Update the list of sessions for the online list [ microtime => sessionID ] */
|
||||
if ( ! $group->g_hide_online_list )
|
||||
{
|
||||
\IPS\Redis::i()->zAdd( $this->_key( 'session_map' ), time(), 'session_id_' . md5( $data['id'] . \IPS\Settings::i()->sql_pass ), static::$ttl );
|
||||
}
|
||||
|
||||
/* Update users list */
|
||||
if ( $data['uagent_type'] == 'search' )
|
||||
{
|
||||
/* Make a unique row based on IP and user-agent to prevent multiple rows for each spider */
|
||||
\IPS\Redis::i()->zAdd( $this->_key( 'session_online_spiders' ), time(), md5( $data['ip_address'] . $data['browser'] ), static::$ttl );
|
||||
}
|
||||
else if ( $data['member_id'] and ! $group->g_hide_online_list )
|
||||
{
|
||||
\IPS\Redis::i()->zAdd( $this->_key( 'session_online_users' ), time(), $data['member_id'] . '__' . 'session_id_' . md5( $data['id'] . \IPS\Settings::i()->sql_pass ), static::$ttl );
|
||||
}
|
||||
else
|
||||
{
|
||||
/* A guest may have one ip address but multiple devices, but we don't really need to track that */
|
||||
\IPS\Redis::i()->zAdd( $this->_key( 'session_online_guests' ), time(), md5( $data['ip_address'] ), static::$ttl );
|
||||
}
|
||||
|
||||
/* Delete old items */
|
||||
if ( ! \IPS\Redis::i()->get( $this->_key( 'session_cleanup' ) ) )
|
||||
{
|
||||
/* Do a little clean up */
|
||||
\IPS\Redis::i()->zRemRangeByScore( $this->_key( 'session_map' ), 0, time() - static::$ttl );
|
||||
\IPS\Redis::i()->zRemRangeByScore( $this->_key( 'session_online_spiders' ), 0, time() - static::$ttl );
|
||||
\IPS\Redis::i()->zRemRangeByScore( $this->_key( 'session_online_users' ), 0, time() - static::$ttl );
|
||||
\IPS\Redis::i()->zRemRangeByScore( $this->_key( 'session_online_guests' ), 0, time() - static::$ttl );
|
||||
|
||||
/* And do it again in 3ish mins */
|
||||
\IPS\Redis::i()->setEx( $this->_key( 'session_cleanup' ), 180, time() );
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete from the session engine
|
||||
*
|
||||
* @param string $sessionId Session ID
|
||||
* @return void
|
||||
*/
|
||||
public function deleteSession( $sessionId )
|
||||
{
|
||||
$data = $this->loadSession( $sessionId );
|
||||
\IPS\Redis::i()->delete( $this->_key( 'session_id_' . md5( $sessionId . \IPS\Settings::i()->sql_pass ) ) );
|
||||
\IPS\Redis::i()->zDelete( $this->_key( 'session_map' ), 'session_id_' . md5( $sessionId . \IPS\Settings::i()->sql_pass ) );
|
||||
\IPS\Redis::i()->zDelete( $this->_key( 'session_online_spiders' ), md5( $data['ip_address'] . $data['browser'] ) );
|
||||
\IPS\Redis::i()->zDelete( $this->_key( 'session_online_users' ), $data['member_id'] . '__' . 'session_id_' . md5( $data['id'] . \IPS\Settings::i()->sql_pass ) );
|
||||
\IPS\Redis::i()->zDelete( $this->_key( 'session_online_guests' ), md5( $data['ip_address'] ) );
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete from the session engine
|
||||
*
|
||||
* @param int $memberId You can probably figure this out right?
|
||||
* @param string|NULL $userAgent User Agent [optional]
|
||||
* @param array|NULL $keepSessionIds Array of session ids to keep [optional]
|
||||
* @return void
|
||||
*/
|
||||
public function deleteByMember( $memberId, $userAgent=NULL, $keepSessionIds=NULL )
|
||||
{
|
||||
if ( ! is_array( $keepSessionIds ) )
|
||||
{
|
||||
$keepSessionIds = array( $keepSessionIds );
|
||||
}
|
||||
|
||||
$sessionMap = \IPS\Redis::i()->zRange( 'session_map', 0, -1 );
|
||||
|
||||
foreach( $sessionMap as $index => $redisKey )
|
||||
{
|
||||
$session = \IPS\Redis::i()->hMGet( $redisKey, array( 'data' ) );
|
||||
|
||||
$sessionMap[ $index ] = \IPS\Redis::i()->decode( $session['data'] );
|
||||
}
|
||||
|
||||
foreach( $sessionMap as $session )
|
||||
{
|
||||
$delete = false;
|
||||
if ( $session['member_id'] == $memberId )
|
||||
{
|
||||
$delete = true;
|
||||
}
|
||||
|
||||
if ( $userAgent and $userAgent != $session['browser'] )
|
||||
{
|
||||
$delete = false;
|
||||
}
|
||||
|
||||
if ( $keepSessionIds and in_array( $session['id'], $keepSessionIds ) )
|
||||
{
|
||||
$delete = false;
|
||||
}
|
||||
|
||||
if ( $delete )
|
||||
{
|
||||
$this->deleteSession( $session['id'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all active session keys
|
||||
*
|
||||
* @return array of session IDs
|
||||
*/
|
||||
public function getSessionIds()
|
||||
{
|
||||
if ( $result = \IPS\Redis::i()->zRangeByScore( 'session_map', '-inf', '+inf', array( 'withscores' => false ) ) )
|
||||
{
|
||||
return $result;
|
||||
}
|
||||
|
||||
return array();
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete from the session engine
|
||||
*
|
||||
* @param int $memberId You can probably figure this out right?
|
||||
* @return array|FALSE
|
||||
*/
|
||||
public function getLatestMemberSession( $memberId )
|
||||
{
|
||||
$redis = \IPS\Redis::i()->zRevRangeByScore( 'session_online_users', '+inf', '-inf', array('withscores' => FALSE, 'alpha' => TRUE ) );
|
||||
|
||||
foreach( $redis as $data )
|
||||
{
|
||||
list( $id, $sessionKey ) = explode( '__', $data );
|
||||
|
||||
if ( $id == $memberId )
|
||||
{
|
||||
if ( $result = \IPS\Redis::i()->hGetAll( $this->_key( $sessionKey ) ) )
|
||||
{
|
||||
return \IPS\Redis::i()->decode( $result['data'] );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear sessions - abstracted so it can be called externally without initiating a session
|
||||
*
|
||||
* @param int $timeout Sessions older than the number of seconds provided will be deleted
|
||||
* @return void
|
||||
*/
|
||||
public static function clearSessions( $timeout )
|
||||
{
|
||||
/* Remove the public facing items. This is only called by PHP's session gc so individual sessions do not need removing as they are cleaned by Redis' TTL */
|
||||
\IPS\Redis::i()->zRemRangeByScore( 'session_map', 0, time() - $timeout );
|
||||
\IPS\Redis::i()->zRemRangeByScore( 'session_online_spiders', 0, time() - $timeout );
|
||||
\IPS\Redis::i()->zRemRangeByScore( 'session_online_users', 0, time() - $timeout );
|
||||
\IPS\Redis::i()->zRemRangeByScore( 'session_online_guests', 0, time() - $timeout );
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns a key to be stored with Redis
|
||||
*
|
||||
* @param string $key Key suffix
|
||||
* @return string
|
||||
*/
|
||||
protected function _key( $key )
|
||||
{
|
||||
return $key;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all online users (but not spiders)
|
||||
*
|
||||
* @param int $flags Bitwise flags
|
||||
* @param array $skipGroups Ignore members in these groups
|
||||
* @param array|NULL $limit Limit [ offset, limit ]
|
||||
* @param int $memberGroup Limit by a specific member group ID
|
||||
* @param boolean $showAnonymous Show anonymously logged in peoples?
|
||||
* @param boolean $includeAllGroups Include all groups? Used for statistics primarily.
|
||||
* @return array
|
||||
*/
|
||||
public function getOnlineUsers( $flags=0, $sort='desc', $limit=NULL, $memberGroup=NULL, $showAnonymous=FALSE, $includeAllGroups=FALSE )
|
||||
{
|
||||
$results = \IPS\Redis::i()->lRange('session_onlinelist', 0, -1 );
|
||||
|
||||
if ( ! $results )
|
||||
{
|
||||
$options = array(
|
||||
'sort' => $sort === 'asc' ? 'asc' : 'desc',
|
||||
'store' => \IPS\Redis::i()->prefix . 'session_onlinelist',
|
||||
'alpha' => true,
|
||||
'by' => 'nosort ' . $sort === 'asc' ? 'asc' : 'desc',
|
||||
'ttl' => 60,
|
||||
'get' => array(
|
||||
$this->_key( \IPS\Redis::i()->prefix ) . '*->member_id',
|
||||
$this->_key( \IPS\Redis::i()->prefix ) . '*->member_name',
|
||||
$this->_key( \IPS\Redis::i()->prefix ) . '*->seo_name',
|
||||
$this->_key( \IPS\Redis::i()->prefix ) . '*->member_group',
|
||||
$this->_key( \IPS\Redis::i()->prefix ) . '*->login_type',
|
||||
$this->_key( \IPS\Redis::i()->prefix ) . '*->data'
|
||||
)
|
||||
);
|
||||
|
||||
\IPS\Redis::i()->sort( $this->_key( 'session_map' ), $options );
|
||||
|
||||
$results = \IPS\Redis::i()->lRange('session_onlinelist', 0, -1 );
|
||||
}
|
||||
|
||||
/* Sort returns a flat array, so [ 1, matt, matt, 4, 0, 2, Joe, joe, 3, 0 .. ] so we need to build that into an associative array we can work with */
|
||||
$return = array();
|
||||
$i = 0;
|
||||
|
||||
while( $i < count( $results ) )
|
||||
{
|
||||
$fields = array();
|
||||
$data = NULL;
|
||||
foreach( array( 'member_id', 'member_name', 'seo_name', 'member_group', 'login_type', 'data' ) as $field )
|
||||
{
|
||||
if ( $field === 'data' )
|
||||
{
|
||||
$data = \IPS\Redis::i()->decode( $results[ $i++ ] );
|
||||
}
|
||||
else
|
||||
{
|
||||
$fields[ $field ] = $results[ $i++ ];
|
||||
}
|
||||
}
|
||||
|
||||
if ( is_array( $data ) AND count( $data ) )
|
||||
{
|
||||
/* Have we already fetched this member? */
|
||||
if ( $fields['member_id'] and isset( $return[ $fields['member_id'] ] ) )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$return[ $fields['member_id'] ? $fields['member_id'] : $data['ip_address'] ] = array_merge( $data, $fields );
|
||||
}
|
||||
}
|
||||
|
||||
if ( $flags )
|
||||
{
|
||||
$members = array();
|
||||
foreach( $return as $id => $data )
|
||||
{
|
||||
/* No members */
|
||||
if ( ! ( $flags & static::ONLINE_MEMBERS ) )
|
||||
{
|
||||
if ( $data['member_id'] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( ! ( $flags & static::ONLINE_GUESTS ) )
|
||||
{
|
||||
if ( ! $data['member_id'] )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
if ( $memberGroup and $data['member_group'] != $memberGroup )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if ( ! $showAnonymous and $data['login_type'] == \IPS\Session\Front::LOGIN_TYPE_ANONYMOUS )
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
$members[ $id ] = $data;
|
||||
}
|
||||
|
||||
/* Count only? */
|
||||
if ( $flags & static::ONLINE_COUNT_ONLY )
|
||||
{
|
||||
return count( $members );
|
||||
}
|
||||
|
||||
if ( $limit )
|
||||
{
|
||||
return array_slice( $members, $limit[0], $limit[1], TRUE );
|
||||
}
|
||||
|
||||
return $members;
|
||||
}
|
||||
|
||||
return $return;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch all members active at a specific location
|
||||
*
|
||||
* @param string $app Application directory (core, forums, etc)
|
||||
* @param string $module Module
|
||||
* @param string $controller Controller
|
||||
* @param int $id Current item ID (empty if none)
|
||||
* @param string $url Current viewing URL
|
||||
* @return array
|
||||
*/
|
||||
public function getOnlineMembersByLocation( $app, $module, $controller, $id, $url )
|
||||
{
|
||||
$members = array();
|
||||
|
||||
foreach( $this->getOnlineUsers( 0, 'desc' ) as $member )
|
||||
{
|
||||
if ( ! \IPS\Member\Group::load( $member['member_group'] )->g_hide_online_list and $member['current_appcomponent'] == $app and $member['current_module'] == $module and $member['current_controller'] = $controller and $member['current_id'] = $id )
|
||||
{
|
||||
if ( $url and mb_stristr( $member['location_url'], $url ) )
|
||||
{
|
||||
$members[ $member['member_id'] ] = array(
|
||||
'member_id' => $member['member_id'],
|
||||
'member_name' => $member['member_name'],
|
||||
'seo_name' => $member['seo_name'],
|
||||
'member_group' => $member['member_group'],
|
||||
'login_type' => $member['login_type'],
|
||||
'in_editor' => $member['in_editor']
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return $members;
|
||||
}
|
||||
}
|
||||
Reference in new issue
Block a user