redis = make(Redis::class); } /** * 签到 * * @param string $userId * @return int */ public function doSigns(string $userId): bool { $day = date('d') - 1; $date = date('Y-m'); return $this->redis->setbit($this->buildSignKey($userId, $date), (int)$day, true); } /** * 统计连续签到次数 * 统计的是连续的签到次数,按业务需求改为七天的 * * @param string $userId * @return int */ public function getContinuousSignCount(string $userId): int { $day = date('d'); $lastMonthCount = 0; if ($day == '1' || $day == '01') { $lastMonthCount = $this->lastMonthContinuousSignCount($userId); } $date = date('Y-m'); $key = $this->buildSignKey($userId, $date); //获取本月的二进制数据 $nowContinuousStr = $this->redis->rawCommand('BITFIELD', $key, 'GET', 'u' . (int)$day, 0); //获取连续签到天数 if ($nowContinuousStr) { $count = $this->countContinuousSignCount($nowContinuousStr, (int)$day); } else { $count = 0; } $count = $count + $lastMonthCount; if ($count > 7) { $count = 7; } return $count; } /** * 检查用户是否签到 * * @param string $userId * @param string $date * @return int */ public function checkSign(string $userId, string $date): int { $day = date('d') - 1; return $this->redis->getBit($this->buildSignKey($userId, $date), $day); } /** * 统计上个月连续签到总数 * * @param string $userId * @return int */ public function lastMonthContinuousSignCount(string $userId): int { $date = date('Ym', strtotime('-1 month')); //上个月最后一天 $day = date("d", strtotime(-date('d') . 'day')); $key = $this->buildSignKey($userId, $date); //获取本月签到的所有二进制数据 $continuousStr = $this->redis->get($key); if ($continuousStr) { $res = $this->countContinuousSignCount($continuousStr, (int)$day); } else { $res = 0; } return $res; } /** * 连续签到计算 * * @param string $continuousStr * @param string $day * @return int */ private function countContinuousSignCount(array $continuousStr, int $day): int { if (!empty($continuousStr)) { $v = $continuousStr[0]; $count = 0; for ($i = 0; $i < $day; $i++) { if ($v >> 1 << 1 == $v) { // 低位为0且非当天说明连续签到中断了 if ($i > 0) { break; } } else { $count += 1; } $v >>= 1; } } else { $count = 0; } return $count; } /** * 构建签到key * * @param string $userId * @param string $date * @return string */ private function buildSignKey(string $userId, string $date): string { return "u:sign:{$userId}:{$date}"; } }