431 lines
13 KiB
PHP
431 lines
13 KiB
PHP
<?php
|
|
/**
|
|
* @file api.php Provides global methods to retrieve active users from the sessions table
|
|
*~TERABYTE_DOC_READY~
|
|
* $Copyright: (c) 2001 - 2011 Invision Power Services, Inc.$
|
|
* $License: http://www.invisionpower.com/company/standards.php#license$
|
|
* $Author: mmecham $
|
|
* @since Friday 12th November 2010 16:58
|
|
* $LastChangedDate: 2012-08-22 05:05:53 -0400 (Wed, 22 Aug 2012) $
|
|
* @version v3.4.8
|
|
* $Revision: 11245 $
|
|
*/
|
|
|
|
/**
|
|
*
|
|
* @class session_api
|
|
* @brief Provides global methods to retrieve active users from the sessions table
|
|
*
|
|
*/
|
|
class session_api
|
|
{
|
|
/**
|
|
* Registry Object Shortcuts
|
|
*
|
|
* @var $registry
|
|
* @var $DB
|
|
* @var $settings
|
|
* @var $request
|
|
* @var $lang
|
|
* @var $member
|
|
* @var $memberData
|
|
* @var $cache
|
|
* @var $caches
|
|
*/
|
|
protected $registry;
|
|
protected $DB;
|
|
protected $settings;
|
|
protected $request;
|
|
protected $lang;
|
|
protected $member;
|
|
protected $memberData;
|
|
protected $cache;
|
|
protected $caches;
|
|
|
|
private $_sClass = null;
|
|
|
|
const NO_AUTO_SESSION_PARSING = true;
|
|
|
|
/**
|
|
* Constructor
|
|
*
|
|
* @param object $registry Registry object
|
|
* @return @e void
|
|
*/
|
|
public function __construct( ipsRegistry $registry )
|
|
{
|
|
/* Make object */
|
|
$this->registry = $registry;
|
|
$this->DB = $this->registry->DB();
|
|
$this->settings =& $this->registry->fetchSettings();
|
|
$this->request =& $this->registry->fetchRequest();
|
|
$this->lang = $this->registry->getClass('class_localization');
|
|
$this->member = $this->registry->member();
|
|
$this->memberData =& $this->registry->member()->fetchMemberData();
|
|
$this->cache = $this->registry->cache();
|
|
$this->caches =& $this->registry->cache()->fetchCaches();
|
|
}
|
|
|
|
/**
|
|
* Returns a list (with buildProfilePhoto set) of users in an application
|
|
*
|
|
* @param string $app Application folder/key
|
|
* @param array $options Array of options to add/override checks for the query
|
|
* @return @e array Array of found sessions (members, guests, bots, anons)
|
|
*
|
|
* <b>Filters:</b>
|
|
* - cutoff: Specify a different cutoff time rather than using the default setting
|
|
* - addJoins: Add more joins for the query
|
|
* - addWhere: Add more checks for the 'where' part of the query (everything is joined with ' AND ')
|
|
* - overrideWhere: Specify manually the 'where' part of the query, the query must be already compiled
|
|
* - overrideGroup: if set to true the check against the 'gbw_view_online_lists' group setting is skipped
|
|
* - skipParsing: If set to true the parseOnlineEntries from coreExtensions is NOT executed
|
|
* - includeErrors: If set to true the in_error=1 lines are loaded as well from the table
|
|
* - excludeViewer: If set to true skips loading the row for the current session_id, it is required to load the current member viewing the page as sessions table is not updated at this point yet but only on destruct
|
|
*
|
|
* <b>Example Usage:</b>
|
|
* @code
|
|
* $onlineUsers = $this->getUsersIn( 'forums', array( 'cutoff' => 90 ) );
|
|
* $onlineUsers = $this->getUsersIn( 'forums', array( 'cutoff' => 90, 'addJoins' => array( ... ), 'addWhere' => array( ... ) ) );
|
|
* $onlineUsers = $this->getUsersIn( 'forums', array( 'overrideWhere' => "s.current_appcomponent='forums' AND (s.running_time > TIME_A OR s.running_time < TIME_B)" ) );
|
|
* @endcode
|
|
*/
|
|
public function getUsersIn( $app, $options=array() )
|
|
{
|
|
/* App we're checking is not even installed? */
|
|
if ( ! IPSLib::appIsInstalled( $app, false ) )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/* Can't view online lists? */
|
|
if ( empty($options['overrideGroup']) && ! $this->memberData['gbw_view_online_lists'] )
|
|
{
|
|
return array();
|
|
}
|
|
|
|
/* Init vars and check options */
|
|
$return = array( 'stats' => array( 'total' => 0,
|
|
'members' => 0,
|
|
'guests' => 0,
|
|
'bots' => 0,
|
|
'anon' => 0 ),
|
|
'rows' => array( 'members' => array(),
|
|
'bots' => array(),
|
|
'guests' => array(),
|
|
'anon' => array() ),
|
|
'names' => array()
|
|
);
|
|
|
|
$cutoff = empty($options['cutoff']) ? $this->settings['au_cutoff'] : $options['cutoff'];
|
|
$limit = time() - ( $cutoff * 60 );
|
|
$rows = array();
|
|
$NOWJIM = IPS_UNIX_TIME_NOW;
|
|
$cached = array();
|
|
|
|
/* Sort joins */
|
|
$_joins = array( array( 'select' => 'm.*',
|
|
'from' => array( 'members' => 'm' ),
|
|
'where' => 'm.member_id=s.member_id',
|
|
'type' => 'left' ) );
|
|
|
|
if ( isset($options['addJoins']) && is_array($options['addJoins']) && count($options['addJoins']) )
|
|
{
|
|
$_joins = array_merge( $_joins, $options['addJoins'] );
|
|
}
|
|
|
|
/* Sort where.. override? */
|
|
if ( !empty($options['overrideWhere']) && is_string($options['overrideWhere']) )
|
|
{
|
|
$where = $options['overrideWhere'];
|
|
}
|
|
else
|
|
{
|
|
/* Normal where */
|
|
$where = array( "s.current_appcomponent='" . $this->DB->addSlashes( $app ) . "'", 's.running_time > ' . $limit );
|
|
|
|
/* Load error rows? */
|
|
if ( empty($options['includeErrors']) )
|
|
{
|
|
$where[] = 's.in_error=0';
|
|
}
|
|
|
|
/* Add more where parts */
|
|
if ( isset($options['addWhere']) && is_array($options['addWhere']) && count($options['addWhere']) )
|
|
{
|
|
$where = array_merge( $where, $options['addWhere'] );
|
|
}
|
|
|
|
$where = implode( ' AND ', $where );
|
|
}
|
|
|
|
/* We're a viewer too? Get our session separately */
|
|
$_extraWhere = empty($options['excludeViewer']) ? "s.id='{$this->member->session_id}' OR " : '';
|
|
|
|
/* Dee bee */
|
|
$this->DB->build( array( 'select' => 's.*, s.id as row_session_id',
|
|
'from' => array( 'sessions' => 's' ),
|
|
'where' => "{$_extraWhere}({$where})",
|
|
'add_join' => $_joins ) );
|
|
$this->DB->execute();
|
|
|
|
while( $session = $this->DB->fetch() )
|
|
{
|
|
/* Reset for possible bad joins */
|
|
$session['id'] = $session['row_session_id'];
|
|
|
|
/* Update our own session properly? */
|
|
if ( $session['id'] == $this->member->session_id )
|
|
{
|
|
$session = array_merge( $session, $this->member->sessionClass()->returnCurrentSession() );
|
|
}
|
|
|
|
$rows[ $session['running_time'] . '.' . $session['id'] ] = $session;
|
|
}
|
|
|
|
/* No rows? */
|
|
if ( ! count( $rows ) )
|
|
{
|
|
return $return;
|
|
}
|
|
|
|
krsort( $rows );
|
|
|
|
/* Are we parsing online entries or want only the names */
|
|
if ( empty( $options['skipParsing'] ) )
|
|
{
|
|
/* Process them */
|
|
$filename = IPSLib::getAppDir( $app ) . '/extensions/coreExtensions.php';
|
|
|
|
if ( is_file( $filename ) )
|
|
{
|
|
$classToLoad = IPSLib::loadLibrary( $filename, 'publicSessions__' . $app, $app );
|
|
$loader = new $classToLoad();
|
|
|
|
if ( method_exists( $loader, 'parseOnlineEntries' ) )
|
|
{
|
|
$rows = $loader->parseOnlineEntries( $rows );
|
|
}
|
|
}
|
|
|
|
/* No rows? */
|
|
if ( ! count( $rows ) )
|
|
{
|
|
return $return;
|
|
}
|
|
}
|
|
|
|
/* Sort through */
|
|
foreach( $rows as $id => $result )
|
|
{
|
|
$last_date = $this->registry->getClass('class_localization')->getTime( $result['running_time'] );
|
|
|
|
/* ROBOT - or DODOT! */
|
|
if ( strstr( $result['id'], '_session' ) )
|
|
{
|
|
$botname = preg_replace( '/^(.+?)=/', "\\1", $result['id'] );
|
|
|
|
if ( ! $cached[ 'srch_' . $result['member_name'] ] )
|
|
{
|
|
$result = IPSMember::buildProfilePhoto( $result );
|
|
$result['parsedMemberName'] = $result['member_name'];
|
|
$return['rows']['bots'][ $result['id'] ] = $result;
|
|
$return['names'][ $result['id'] ] = $result['parsedMemberName'];
|
|
|
|
$cached[ 'srch_' . $result['member_name'] ]['count'] = 1;
|
|
}
|
|
else
|
|
{
|
|
$cached[ 'srch_' . $result['member_name'] ]['count']++;
|
|
}
|
|
|
|
$return['stats']['bots']++;
|
|
}
|
|
/* Guest */
|
|
else if ( ! $result['member_id'] )
|
|
{
|
|
$result = IPSMember::buildProfilePhoto( 0 );
|
|
$result['parsedMemberName'] = $this->lang->words['global_guestname'];
|
|
$return['rows']['guests'][ $result['id'] ] = $result;
|
|
|
|
$return['stats']['guests']++;
|
|
}
|
|
/* Member */
|
|
else
|
|
{
|
|
if ( empty( $cached[ $result['member_id'] ] ) )
|
|
{
|
|
$cached[ $result['member_id'] ] = 1;
|
|
|
|
$result = IPSMember::buildProfilePhoto( $result );
|
|
$result['parsedMemberName'] = IPSMember::makeNameFormatted( $result['member_name'], $result['member_group'] );
|
|
|
|
/* Reset login type in case the board/group setting got changed */
|
|
$result['login_type'] = IPSMember::isLoggedInAnon( array( 'login_anonymous' => $result['login_type'] ), $result['member_group_id'] );
|
|
|
|
if ( $result['login_type'] )
|
|
{
|
|
if ( $this->memberData['g_access_cp'] || ( $this->memberData['member_id'] == $result['member_id'] ) )
|
|
{
|
|
$result['parsedMemberName'] = IPSMember::makeProfileLink( $result['parsedMemberName'], $result['member_id'], $result['seo_name'] );
|
|
$result['parsedMemberName'] .= '*'; # Add anonymous asterisk
|
|
$return['rows']['anon'][ $result['id'] ] = $result;
|
|
$return['names'][ $result['id'] ] = $result['parsedMemberName'];
|
|
}
|
|
|
|
$return['stats']['anon']++;
|
|
}
|
|
else
|
|
{
|
|
$result['parsedMemberName'] = IPSMember::makeProfileLink( $result['parsedMemberName'], $result['member_id'], $result['seo_name'] );
|
|
$return['rows']['members'][ $result['id'] ] = $result;
|
|
$return['names'][ $result['id'] ] = $result['parsedMemberName'];
|
|
|
|
$return['stats']['members']++;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
/* Process bots */
|
|
foreach( $cached as $name => $val )
|
|
{
|
|
if ( $val['count'] && substr( $name, 0, 5 ) == 'srch_' )
|
|
{
|
|
foreach( $return['rows']['bots'] as $row )
|
|
{
|
|
if ( $row['parsedMemberName'] == substr( $name, 5 ) )
|
|
{
|
|
$return['rows']['bots'][ $row['id'] ]['parsedMemberName'] .= ' (' . $val['count'] . ')';
|
|
$return['rows']['bots'][ $row['id'] ]['member_name'] = $return['rows']['bots'][ $row['id'] ]['parsedMemberName'];
|
|
$return['names'][ $row['id'] ] = $return['rows']['bots'][ $row['id'] ]['parsedMemberName'];
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
$return['stats']['total'] = intval( $return['stats']['bots'] ) + intval( $return['stats']['guests'] ) + intval( $return['stats']['anon'] ) + intval( $return['stats']['members'] );
|
|
|
|
return $return;
|
|
}
|
|
|
|
/**
|
|
* Fetch session by member id
|
|
* @param int Member Id
|
|
* @return array session data
|
|
*/
|
|
public function getSessionByMemberId( $memberId )
|
|
{
|
|
$_session = $this->DB->buildAndFetch( array( 'select' => '*',
|
|
'from' => 'sessions',
|
|
'where' => "member_id=" . intval( $memberId ) ) );
|
|
|
|
if ( $_session['id'] )
|
|
{
|
|
/* Test for browser.... */
|
|
if ( $this->settings['match_browser'])
|
|
{
|
|
if ( $_session['browser'] != substr( $this->member->user_agent, 0, 200 ) )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/* Test for IP Address... */
|
|
if ( $this->settings['match_ipaddress'] )
|
|
{
|
|
if ( $_session['ip_address'] != $this->member->ip_address )
|
|
{
|
|
return false;
|
|
}
|
|
}
|
|
|
|
return $_session;
|
|
}
|
|
|
|
return false;
|
|
}
|
|
|
|
/**
|
|
* Log user in remotely if user is not logged in.
|
|
* @param array Array of member data (member_id, etc) or Id
|
|
*/
|
|
public function logGuestInAsMember( $member )
|
|
{
|
|
if ( is_numeric( $member ) )
|
|
{
|
|
$member = IPSMember::load( $member );
|
|
}
|
|
|
|
/* Check for existing session */
|
|
$ip = ipsRegistry::member()->ip_address;
|
|
$_session = $this->DB->buildAndFetch( array( 'select' => '*',
|
|
'from' => 'sessions',
|
|
'where' => "ip_address='{$ip}'" ) );
|
|
|
|
if ( ! $_session['id'] or ! $_session['member_id'] )
|
|
{
|
|
$this->_getSessionClass()->convertGuestToMember( $member, $member );
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Log user in remotely overwriting a different accounts log in if need be.
|
|
* @param array Array of member data (member_id, etc) or Id
|
|
*/
|
|
public function logInAsMember( $member )
|
|
{
|
|
if ( is_numeric( $member ) )
|
|
{
|
|
$member = IPSMember::load( $member );
|
|
}
|
|
|
|
$this->_getSessionClass()->convertGuestToMember( $member, $member );
|
|
}
|
|
|
|
/**
|
|
* Load session class if not loaded
|
|
*/
|
|
protected function _getSessionClass()
|
|
{
|
|
if ( ! is_object( $this->_sClass ) )
|
|
{
|
|
$classToLoad = IPSLib::loadLibrary( IPS_ROOT_PATH . 'sources/classes/session/publicSessions.php', 'publicSessions' );
|
|
|
|
/**
|
|
* Support for extending the session class
|
|
*/
|
|
if ( is_file( IPS_ROOT_PATH . "sources/classes/session/ssoPublicSessions.php" ) )
|
|
{
|
|
$classToLoadA = IPSLib::loadLibrary( IPS_ROOT_PATH . "sources/classes/session/ssoPublicSessions.php", 'ssoPublicSessions' );
|
|
|
|
/**
|
|
* Does the ssoPublicSessions class exist?
|
|
*/
|
|
if( class_exists( $classToLoadA ) )
|
|
{
|
|
$parent = get_parent_class( $classToLoadA );
|
|
|
|
/**
|
|
* Is it a child of publicSessions
|
|
*/
|
|
if ( $parent == $classToLoad )
|
|
{
|
|
$this->_sClass = new $classToLoadA( self::NO_AUTO_SESSION_PARSING );
|
|
}
|
|
else
|
|
{
|
|
$this->_sClass = new $classToLoad( self::NO_AUTO_SESSION_PARSING );
|
|
}
|
|
}
|
|
}
|
|
else
|
|
{
|
|
$this->_sClass = new $classToLoad( self::NO_AUTO_SESSION_PARSING );
|
|
}
|
|
}
|
|
|
|
return $this->_sClass;
|
|
}
|
|
} |