_pre_cache_key = 'common_session_'; } public function fetch($sid, $ip = false, $uid = false) { if(empty($sid)) { return array(); } $session = $this->get_data_by_pk($sid); if($session && $ip !== false && $ip != "{$session['ip']}") { $session = array(); } if($session && $uid !== false && $uid != $session['uid']) { $session = array(); } return $session; } public function fetch_member($ismember = 0, $invisible = 0, $start = 0, $limit = 0) { if ($ismember < 1 || $ismember > 2) $ismember = 0; // $ismember只有0, 1, 2是合法值 if ($invisible < 1 || $invisible > 2) $invisible = 0; // invisible只有0, 1, 2是合法值 list($ss, $ee) = $this->get_start_and_end($start, $limit); ($invisible == 2) ? $inv_idx = 0 : $inv_idx = 1; // $invisible == 2,相当于sql条件 invisible = 0 ($ismember == 2) ? $uid_idx = 0 : $uid_idx = 1; // $ismember == 2,相当于sql条件 uid = 0 if ($ismember == 0 && $invisible == 0) { $script = <<_pre_cache_key); } elseif ($ismember == 0) { $script = <<_pre_cache_key); } elseif ($invisible == 0) { $script = <<_pre_cache_key); } else { global $_G; $temp_uniq = substr(md5(substr(TIMESTAMP, 0, -3).substr($_G['config']['security']['authkey'], 3, -3)), 1, 8); $script = <<_pre_cache_key); } return $this->array_from_memory_result($data); } public function count_invisible($type = 1) { return memory('zcard', 'idx_invisible_' . $type, $this->_pre_cache_key); } public function count($type = 0) { switch ($type) { case 1: return memory('zcard', 'idx_uid_group_1', $this->_pre_cache_key); case 2: return memory('zcard', 'idx_uid_group_0', $this->_pre_cache_key); default: return memory('zcard', 'idx_lastactivity', $this->_pre_cache_key); } } public function delete_by_session($session, $onlinehold, $guestspan) { if(empty($session) || !is_array($session)) return; $onlinehold = time() - $onlinehold; $guestspan = time() - $guestspan; global $_G; $temp_uniq = substr(md5(substr(TIMESTAMP, 0, -3).substr($_G['config']['security']['authkey'], 3, -3)), 1, 8); $script = << 0) then redis.call("del", prefix..sid) rs[#rs + 1] = bysid end -- lastactivity < onlinehold local byonlinehold = redis.call("ZRANGEBYSCORE", prefix.."idx_lastactivity", 0, onlinehold + 1); for _, sid in ipairs(byonlinehold) do local data = getdata(prefix..sid); if (#data > 0) then redis.call("del", prefix..sid) rs[#rs + 1] = data end end -- uid = 0 and ip = userip local out_hash = prefix..'uid0_ip_'..out_surfix redis.call("ZINTERSTORE", out_hash, 2, prefix.."idx_uid_group_0", prefix.."idx_ip_"..userip, 'AGGREGATE', 'MIN') -- and lastactivity > guestspan local byguestspan = redis.call("ZRANGEBYSCORE", out_hash, guestspan + 1, '+inf') for _, sid in ipairs(byguestspan) do local data = getdata(prefix..sid); if ((#data > 0)) then redis.call("del", prefix..sid) rs[#rs + 1] = data end end redis.call("DEL", out_hash) local byuid = redis.call("SMEMBERS", prefix.."idx_uid_"..uid); for _, sid in ipairs(byuid) do local data = getdata(prefix..sid); if (#data > 0) then redis.call("del", prefix..sid) rs[#rs + 1] = data end end for _, row in ipairs(rs) do redis.call("ZREM", prefix.."idx_ip_"..row[2], row[1]) redis.call("ZREM", prefix.."idx_invisible_"..row[4], row[1]) redis.call("ZREM", prefix.."idx_fid_"..row[5], row[1]) if (row[3] == '0') then redis.call("ZREM", prefix.."idx_uid_group_0", row[1]) else redis.call("ZREM", prefix.."idx_uid_group_1", row[1]) end redis.call("ZREM", prefix.."idx_lastactivity", row[1]) redis.call("SREM", prefix.."idx_uid_"..row[3], row[1]) end return #rs LUA; memory('eval', $script, array($session['sid'], $onlinehold, $guestspan, $session['ip'], $session['uid'] ? $session['uid'] : -1, $temp_uniq), "delete_by_session", $this->_pre_cache_key); } public function fetch_by_uid($uid) { if(empty($uid)) { return false; } $sids = memory('smembers', 'idx_uid_' . $uid, $this->_pre_cache_key); foreach ($sids as $sid) { return $this->get_data_by_pk($sid); } return false; } public function fetch_all_by_uid($uids, $start = 0, $limit = 0) { if(empty($uids)) { return array(); } if (!is_array($uids)) { $uids = array($uids); } $script = <<= start) then local row = redis.call("hmget", prefix..key, "sid", "ip", "uid", "username", "groupid", "invisible", "action", "lastactivity", "lastolupdate", "fid", "tid") rs[#rs + 1] = row if (#rs >= limit) then return rs end end sid_index = sid_index + 1 end argv_index = argv_index + 1 end return rs LUA; list($ss, $ee) = $this->get_start_and_end($start, $limit); $data = memory('eval', $script, array_merge(array($ss, $ee), $uids), "fetch_all_by_uid", $this->_pre_cache_key); return $this->array_from_memory_result($data); } public function update_by_uid($uid, $data) { if(!($uid = dintval($uid)) || empty($data) || !is_array($data)) { return 0; } $script = <<_pre_cache_key); $items = $this->array_from_memory_result($r); memory('pipeline'); foreach ($items as $olditem) { $sid = $olditem['sid']; $data['sid'] = $sid; // $data中可能没有sid memory('hmset', $sid, $data, 0, $this->_pre_cache_key); $this->update_memory_index($sid, $data, $olditem); } memory('commit'); } public function update_max_rows($max_rows) { return TRUE; } public function clear() { return TRUE; } public function count_by_fid($fid) { $fid = dintval($fid); if (!$fid) return 0; global $_G; $temp_uniq = substr(md5(substr(TIMESTAMP, 0, -3).substr($_G['config']['security']['authkey'], 3, -3)), 1, 8); $script = << 0 and fid=fid and invisible = 0 redis.call("ZINTERSTORE", out_hash, 3, prefix.."idx_uid_group_1", prefix.."idx_fid_"..fid, prefix.."idx_invisible_0", 'AGGREGATE', 'MIN') local rs = redis.call("ZCARD", out_hash) redis.call("DEL", out_hash) return rs LUA; $data = memory('eval', $script, array($fid, $temp_uniq), "count_by_fid", $this->_pre_cache_key); return $data; } public function fetch_all_by_fid($fid, $limit = 12) { $fid = dintval($fid); if (!$fid) return array(); global $_G; $temp_uniq = substr(md5(substr(TIMESTAMP, 0, -3).substr($_G['config']['security']['authkey'], 3, -3)), 1, 8); $script = << 0 and fid=fid and invisible = 0 redis.call("ZINTERSTORE", out_hash, 3, prefix.."idx_uid_group_1", prefix.."idx_fid_"..fid, prefix.."idx_invisible_0", 'AGGREGATE', 'MIN') local keys = redis.call("ZREVRANGE", out_hash, 0, limit - 1) redis.call("DEL", out_hash) local rs = {} for _, key in ipairs(keys) do local row = redis.call("hmget", prefix..key, "uid", "groupid", "username", "invisible", "lastactivity") rs[#rs + 1] = row end return rs LUA; $data = memory('eval', $script, array($fid, $limit, $temp_uniq), "fetch_all_by_fid", $this->_pre_cache_key); $result = array(); foreach ($data as $row) { $item = array(); $item['uid'] = $row[0]; $item['groupid'] = $row[1]; $item['username'] = $row[2]; $item['invisible'] = $row[3]; $item['lastactivity'] = $row[4]; $result[] = $item; } return $result; } public function count_by_ip($ip) { if (empty($ip)) return 0; return memory('zcard', 'idx_ip_' . $ip, $this->_pre_cache_key); } public function fetch_all_by_ip($ip, $start = 0, $limit = 0) { if (empty($ip)) return array(); list($ss, $ee) = $this->get_start_and_end($start, $limit); $script = <<_pre_cache_key); return $this->array_from_memory_result($data); } public function insert($data, $return_insert_id = false, $replace = false, $silent = false) { $id = $data['sid']; memory('pipeline'); memory('hmset', $id, $data, 0, $this->_pre_cache_key); $this->update_memory_index($id, $data); memory('commit'); } public function update($val, $data, $unbuffered = false, $low_priority = false) { $olddata = $this->get_data_by_pk($val); memory('pipeline'); memory('hmset', $val, $data, 0, $this->_pre_cache_key); $this->update_memory_index($val, $data, $olddata); memory('commit'); } private function update_memory_index($sid, $newdata, $olddata = array()) { if (!empty($olddata) && !isset($olddata['lastactivity'])) { return; } if (!empty($olddata) && !isset($newdata['lastactivity'])) { $newdata['lastactivity'] = $olddata['lastactivity']; } foreach ($newdata as $col => $value) { if (!in_array($col, array("ip", "uid", "fid", "lastactivity", "invisible"))) continue; if (isset($olddata[$col])) { if ($olddata[$col] === $value && $olddata['lastactivity'] === $newdata['lastactivity']) { continue; } switch ($col) { case 'ip': memory('zrem', "idx_ip_" . $olddata[$col], $sid, 0, $this->_pre_cache_key); break; case 'lastactivity': memory('zrem', 'idx_lastactivity', $sid, 0, $this->_pre_cache_key); break; case 'fid': memory('zrem', "idx_fid_" . $olddata[$col], $sid, 0, $this->_pre_cache_key); break; case 'invisible': memory('zrem', "idx_invisible_" . $olddata[$col], $sid, 0, $this->_pre_cache_key); break; case 'uid': memory('zrem', "idx_uid_group_" . ($olddata[$col] == 0 ? '0' : '1'), $sid, 0, $this->_pre_cache_key); memory('srem', "idx_uid_" . $olddata[$col], $sid, 0, $this->_pre_cache_key); break; default: continue 2; } } switch ($col) { case 'ip': case 'fid': case 'invisible': memory('zadd', 'idx_' . $col . "_" . $value, $sid, $newdata['lastactivity'], $this->_pre_cache_key); break; case 'lastactivity': memory('zadd', 'idx_lastactivity', $sid, $newdata['lastactivity'], $this->_pre_cache_key); break; case 'uid': memory('zadd', "idx_uid_group_" . ($value == 0 ? '0' : '1'), $sid, $newdata['lastactivity'], $this->_pre_cache_key); memory('sadd', 'idx_uid_' . $value, $sid, 0, $this->_pre_cache_key); break; default: continue 2; } } } private function array_from_memory_result($data) { $result = array(); foreach ($data as $row) { $item = array(); $item['sid'] = $row[0]; $item['ip'] = $row[1]; $item['uid'] = $row[2]; $item['username'] = $row[3]; $item['groupid'] = $row[4]; $item['invisible'] = $row[5]; $item['action'] = $row[6]; $item['lastactivity'] = $row[7]; $item['lastolupdate'] = $row[8]; $item['fid'] = $row[9]; $item['tid'] = $row[10]; $result[] = $item; } return $result; } private function get_data_by_pk($sid) { $data = memory('hgetall', $sid, $this->_pre_cache_key); return $data; } private function get_start_and_end($start, $limit) { $limit = intval($limit > 0 ? $limit : 0); $start = intval($start > 0 ? $start : 0); if ($start > 0 && $limit > 0) { return array($start, $start + $limit - 1); } elseif ($limit > 0) { return array(0, $limit - 1); } elseif ($start > 0) { return array(0, $start - 1); } else { return array(0, -1); } } } ?>