因为 @vimac 的答案没有解决最近一小时问题,以下仅提供个思路,细节还可以完善
// 存储失败次数时间戳
$key = "user:{$user_id}:login_failed";
$login_failed = $mem->get($key) or array();
$allow_times = 12;
if(! checkAllowTimes($login_failed, $allow_times)){
throw new Exception("allow times max", 1);
}
if(! passValid($user_id, $password)){
array_unshift($login_failed, time());
// 最多存 12 条记录
if(count($login_failed) > $allow_times){
$login_failed = array_slice($login_failed, 0, $allow_times);
}
$mem->set($key, $login_failed, 3600);
}else{
// 登录成功删除失败记录,取决于是连续失败还是累计失败?
$mem->delete($key);
// ...
}
function passValid($user_id, $password){
// ...
// 伪代码
return true or false;
}
function checkAllowTimes($login_failed, $allow_times){
$last_hour = strtotime('1 hours ago');
for($i = 0; $i < count($login_failed); $i++){
// 如果已经登录失败 12 次
if($i >= $allow_times - 1){
return false;
}
// 1 小时前的登录记录不检索
if($login_failed[$i] <= $last_hour){
return true;
}
}
return true;
}