<?php
!defined('P_W') && exit('Forbidden');
class PW_OnlineService{
	
	var $page_index = array('index' => 1, 'thread' => 2, 'read' => 3, 'cate' => 4, 'mode' => 5, 'other' => 6);
	var $db;	
	// 對于同一個ip的新游客，當給其分配新的token時，需要將lastvisit距離當前timestamp在$tokenTime秒內的游客刪除
	var $tokenTime = 60;
	
	/**
	 * 更新在線的登錄用戶信息
	 *
	 * @return boolean
	 */
	function updateOnlineUser() { 
		global $fid, $tid, $timestamp, $winduid, $windid, $onlineip, $groupid, $wind_in, $db_onlinetime, $db_ipstates, $db_today, $lastvisit, $tdtime,$db;
		if ($winduid < 1) return false;
		
		$ifhide = $GLOBALS['_G']['allowhide'] && GetCookie('hideid') ? 1 : 0;
		$pwSQL = S::sqlSingle(array('uid' => $winduid, 
									'ip' => $this->_ip2long($onlineip), 
									'groupid' => $groupid, 
									'username' => $windid, 
									'lastvisit' => $timestamp, 
									'fid' => $fid, 
									'tid' => $tid, 
									'action' => $this->page_index[$wind_in], 
									'ifhide' => $ifhide));
		// 間隔一段時間刪除過期用戶，避免頻繁刪除導致性能下降
		if ($timestamp % 20 == 0){
			$db->update('DELETE FROM pw_online_user WHERE lastvisit<' . S::sqlEscape($timestamp - $db_onlinetime));
		}
		return $db->update('REPLACE INTO pw_online_user SET ' . $pwSQL);
	}
	
	/**
	 * 更新在線的游客信息
	 *
	 * @return boolean
	 */
	function updateOnlineGuest(){
		global $fid, $tid, $timestamp, $onlineip,$db_onlinetime,$wind_in,$db;
		if (!($guestInfo = $this->getGuestInfo())){
			return false;
		}

		$ifhide = $GLOBALS['_G']['allowhide'] && GetCookie('hideid') ? 1 : 0;
		if ($guestInfo['token'] == 0){
			// 刪除過期的游客或者同IP在60秒內更新過的游客（防止惡意刷人數的行為）
			$db->update('DELETE FROM pw_online_guest WHERE lastvisit<' . S::sqlEscape($timestamp - $db_onlinetime) . 
				' OR (ip = ' . S::sqlEscape($guestInfo['ip']) . ' AND  lastvisit>' . S::sqlEscape($timestamp - $this->tokenTime) . ')');
			$token = rand(1,255);
			$this->setGuestToken($token);
		} else {
			// 間隔一段時間刪除過期用戶，避免頻繁刪除導致性能下降
			if ($timestamp % 20 == 0){
				$db->update('DELETE FROM pw_online_guest WHERE lastvisit<' . S::sqlEscape($timestamp - $db_onlinetime));
			}
			$token = $guestInfo['token'];
		}

		$pwSQL = S::sqlSingle(array('ip' => $guestInfo['ip'], 
									'token' => $token,
									'lastvisit' => $timestamp, 
									'fid' => $fid, 
									'tid' => $tid, 
									'action' => $this->page_index[$wind_in], 
									'ifhide' => $ifhide));
		$db->update("REPLACE INTO pw_online_guest SET " . $pwSQL);
	}
	
	/**
	 * 當用戶登錄時調用此接口，刪除其在“在線游客”表的記錄
	 *
	 * @return boolean
	 */
	function deleteOnlineGuest($guestInfo = null){
		if (!$guestInfo  && !($guestInfo = $this->getGuestInfo())){
			return false;
		}
		global $db;
		return $db->update('DELETE FROM pw_online_guest WHERE ip=' . S::sqlEscape($guestInfo['ip']) . ' AND token = ' .  S::sqlEscape($guestInfo['token']));
	}
	
	/**
	 * 當用戶退出是調用此接口，刪除其在“在線用戶”表的記錄
	 *
	 * @return boolean
	 */
	function deleteOnlineUser($userId){
		if (($userId = intval($userId)) < 1) return false;
		global $db;
		return $db->update("DELETE FROM pw_online_user WHERE uid=" . S::sqlEscape($userId));
	}
	
	/**
	 * 獲取所有在線的登錄用戶列表, 專為sort.php統計在線人數使用
	 *
	 * @param integer $start 頁碼
	 * @param integer $perpage 每頁數目
	 * @param integer &$number 回傳參數，所有在線人數
	 * @return array
	 */
	function getAllOnlineWithPaging($start, $perpage, &$number){
		$online_user_num = $this->countOnlineUser();
		$online_guest_num = $this->countOnlineGuest();
		if ($start * $perpage <= $online_user_num){
			$all = $this->getOnlineUser($start, $perpage);
		}else if (($start-1) * $perpage + 1> $online_user_num){
			$all = $this->getOnlineGuest($start, $perpage);
		}else{
			$all = array_merge($this->getOnlineUser($start, $perpage), $this->getOnlineGuest(1, $perpage));
		}
		$number = $online_user_num + $online_guest_num;
		return $all;
	}
	
	/**
	 * 獲取所有在線用戶列表，包括登錄用戶和游客, 不提供分頁
	 *
	 * @return array
	 */
	function getAllOnline(){
		return array_merge((array)$this->getOnlineUser(), (array)$this->getOnlineGuest());
	}		
		
	/**
	 * 獲取所有在線用戶，支持分頁，若不給$start和$perpage參數則獲取全部用戶
	 *
	 * @param int $start 
	 * @param int $perpage
	 * @return array
	 */
	function getOnlineUser($start = 0, $perpage = 20){
		global $db;
		$limit = $start < 1 ? '' : S::sqlLimit(($start - 1) * $perpage, $perpage);
		$query = $db->query('SELECT * FROM pw_online_user ' . $limit);
		$page_reverse_index = array_flip($this->page_index);
		$users = array();
		while ($rt = $db->fetch_array($query)){
			$rt['ip'] = long2ip($rt['ip']);
			$rt['action'] = $page_reverse_index[$rt['action']];
			$users[] = $rt;
		}
		return $users;
	}
	
	/**
	 * 獲取所有在線游客，支持分頁，若不給$start和$perpage參數則獲取全部用戶
	 *
	 * @param int $start 
	 * @param int $perpage
	 * @return array
	 */
	function getOnlineGuest($start = 0, $perpage = 20){
		global $db;
		$limit = $start < 1 ? '' : S::sqlLimit(($start - 1) * $perpage, $perpage);
		$query = $db->query('SELECT * FROM pw_online_guest ' . $limit);
		$page_reverse_index = array_flip($this->page_index);
		$guests = array();
		while ($rt = $db->fetch_array($query)){
			$rt['ip'] = long2ip($rt['ip']);
			$rt['action'] = $page_reverse_index[$rt['action']];
			$guests[] = $rt;
		}
		return $guests;
	}
	
	/**
	 * 獲取所有在線用戶的用戶名，以uid作為key
	 *
	 * @return array
	 */
	function getOnlineUserName(){
		global $db;
		$query = $db->query('SELECT uid, username FROM pw_online_user');
		$users = array();
		while ($rt = $db->fetch_array($query)){
			$users[$rt['uid']] = $rt['username'];
		}
		return $users;		
	}
	
	/**
	 * 獲取某一版塊的在線用戶
	 *
	 * @param integer $forumId
	 * @return array
	 */
	function getOnlineUserByForumId($forumId){
		global $db;
		if (($forumId = intval($forumId)) < 1) return false;
		$query = $db->query('SELECT * FROM pw_online_user WHERE fid=' . S::sqlEscape($forumId));
		$onlineUsers = array();
		while($rt = $db->fetch_array($query)){
			$onlineUsers[] = $rt;
		}
		return $onlineUsers;
	}
	
	/**
	 * 根據userid從pw_online_user表獲取一條記錄
	 *
	 * @param integer $userId
	 * @return array
	 */
	function getOnlineUserByUserId($userId){
		global $db;
		return $db->get_one('SELECT * FROM pw_online_user WHERE uid=' . S::sqlEscape($userId));
	}
	
	/**
	 * 統計在線的登錄用戶數目
	 *
	 * @return integer
	 */
	function countOnlineUser(){
		global $db;
		$rt = $db->get_one('SELECT COUNT(*) AS sum FROM pw_online_user');
		return $rt ? $rt['sum'] : $rt;
	}	
	
	/**
	 * 統計所有在線游客數目
	 *
	 * @return integer
	 */
	function countOnlineGuest(){
		global $db;
		$rt = $db->get_one("SELECT COUNT(*) AS sum FROM pw_online_guest");
		return $rt ? $rt['sum'] : $rt;		
	}
	
	/**
	 * 統計所有在線用戶，包括登錄用戶和游客
	 *
	 * @return integer
	 */
	function countAllOnline(){
		return (int)$this->countOnlineUser() + (int)$this->countOnlineGuest();
	}
	
	/**
	 * 統計指定ip的在線人數
	 *
	 * @param integer $ip
	 * @return integer
	 */
	function countOnlineGuestByIp($ip){
		if (!$ip) return false;
		global $db;
		$rt = $db->get_one('SELECT COUNT(*) AS sum FROM pw_online_guest WHERE ip = ' . S::sqlEscape($ip) );
		return $rt ? $rt['sum'] : 0;
	}
	
	/**
	 * 寫游客令牌到cookie
	 *
	 */
	function setGuestToken($token = 0){
		return $token ? Cookie('oltoken', StrCode($this->_ip2long($GLOBALS['onlineip']) . "\t" . $token)) : Cookie('oltoken', 'init');
	}

	/**
	 * 寫當前在線會員數和在線游客數到cookie
	 *
	 */
	function setOnlineNumber(){
		return Cookie('online_info',  $GLOBALS['timestamp'] . "\t" .(int)$this->countOnlineUser() . "\t" . $this->countOnlineGuest());
	}
	
	/**
	 * 從cookie獲取游客信息
	 * ipchange 表示ip是否改變了，針對adsl的用戶
	 *
	 * @return array
	 */
	function getGuestInfo(){
		static $guestInfo = null;
		if (isset($guestInfo)) return $guestInfo;		
		list($ip, $token) = explode("\t", StrCode(GetCookie('oltoken'), 'DECODE'));
		$onlineip = $this->_ip2long($GLOBALS['onlineip']);
		if ($ip != $onlineip || $token > 254 || $token < 1) {
			$guestInfo = array('ip' => $onlineip, 'token' => 0);
			$guestInfo['ipchange'] = ($ip != $onlineip && $token > 0 && $token < 255) ? true : false;
		}else {
			$guestInfo = array('ip' => $onlineip, 'token' => $token , 'ipchange' => false);
		}
		return $guestInfo;
	}	
	
	/**
	 * 封裝了ip2long函數，主要是ip地址可能是'unknown'
	 *
	 * @param string $ip
	 * @return int
	 */
	function _ip2long($ip){
		/**
		$ip = ip2long($ip);
		if ($ip === false || $ip == -1) $ip = ip2long('0.0.0.0');
		return $ip;
		**/
		list(, $ip) = unpack('l',pack('l',ip2long($ip)));
		return $ip;		
	}
}

