1. 程式人生 > >利用redis實現使用者簽到

利用redis實現使用者簽到

很多網站都提供了簽到功能(這裡不考慮資料落地事宜),並且需要展示最近一個月的簽到情況,如果使用bitmap我們怎麼做?一言不合亮程式碼!

<?php
$redis = new Redis();
$redis->connect('127.0.0.1');
 
 
//使用者uid
$uid = 1;
 
//記錄有uid的key
$cacheKey = sprintf("sign_%d", $uid);
 
//開始有簽到功能的日期
$startDate = '2017-01-01';
 
//今天的日期
$todayDate = '2017-01-21';
 
//計算offset
$startTime = strtotime($startDate);
$todayTime = strtotime($todayDate);
$offset = floor(($todayTime - $startTime) / 86400);
 
echo "今天是第{$offset}天" . PHP_EOL;
 
//簽到
//一年一個使用者會佔用多少空間呢?大約365/8=45.625個位元組,好小,有木有被驚呆?
$redis->setBit($cacheKey, $offset, 1);
 
//查詢簽到情況
$bitStatus = $redis->getBit($cacheKey, $offset);
echo 1 == $bitStatus ? '今天已經簽到啦' : '還沒有簽到呢';
echo PHP_EOL;
 
//計算總簽到次數
echo $redis->bitCount($cacheKey) . PHP_EOL;
 
/**
* 計算某段時間內的簽到次數
* 很不幸啊,bitCount雖然提供了start和end引數,但是這個說的是字串的位置,而不是對應"位"的位置
* 幸運的是我們可以通過get命令將value取出來,自己解析。並且這個value不會太大,上面計算過一年一個使用者只需要45個位元組
* 給我們的網站定一個小目標,執行30年,那麼一共需要1.31KB(就問你屌不屌?)
*/
//這是個錯誤的計算方式
echo $redis->bitCount($cacheKey, 0, 20) . PHP_EOL;

BITCOUNT的坑

redis> BITCOUNT bits
(integer) 0
redis> SETBIT bits 1 1          
(integer) 0
redis> SETBIT bits 2 1
(integer) 0
redis> BITCOUNT bits
(integer) 2
redis> BITCOUNT bits 2 -1
(integer) 0

為什麼我設定了bitcount的start後會取不到值?
“redis的setbit修改的是bit位置,而bitcount檢查的是byte位置,兩者相差有8的倍數”,再看文件確實是有這個說明,不過太不明顯了
所以在setbit 前把offset * 8 才可以。

$redis = new Redis();
$redis->connect('127.0.0.1', 6379, 10);
 
// 乘以8的原因是這個操作修改的是bit位置
$start = 1;
$offset = $start * 8;
$redis->setBit('bit', $offset, 1);
$count = $redis->bitCount('bit', $start, -1);
var_dump($count);

 

參考:https://blog.csdn.net/fly910905/article/details/82629687