<?php session_start(); $time = 60;//60秒 $count = 10; //可访问 10次 //第一次初始化 if(!isset($_SESSION['count'])){ $_SESSION['count'] = 1; $_SESSION['time'] = time(); $_SESSION['cha'] = 0; $_SESSION['status'] = 'success'; print_r($_SESSION); }else { $now = time(); $cha = $now - $_SESSION['time']; $avg = intval($time / $count);//平均多少秒可获得一次机会 //如果超过次数 if($_SESSION['count'] > $count){ //如果时差超过平均可获得次数的时长 if($cha > $avg){ $_SESSION['count'] -= intval($cha / $avg); //计算可得多少次机会 $_SESSION['count'] = max($_SESSION['count'], 0);//修正次数不能为负。 $_SESSION['count']++; $_SESSION['time'] = $now; $_SESSION['cha'] = $cha; $_SESSION['status'] = 'success'; print_r($_SESSION); }else{ //如果时差没有超过 $avg ,则还是失败。 $_SESSION['cha'] = $cha; $_SESSION['status'] = 'fail'; print_r($_SESSION); } }else{ //如果没超过次数正常访问 if($cha > $avg) { $_SESSION['count'] -= intval($cha / $avg); //计算可得多少次机会 $_SESSION['count'] = max($_SESSION['count'], 0);//修正次数不能为负。 } $_SESSION['count']++; $_SESSION['time'] = $now; $_SESSION['cha'] = $cha; $_SESSION['status'] = 'success'; print_r($_SESSION); } }
如果要精确计算,则要记录每次访问以元素的形式记录时间戳,到数组,每次请求的时候,遍历数组元素中的时间戳,与当前时间比较,清理掉 N分钟之前的元素,然后再计算个数,如果个数没超,则允许,反之不行。
/** * 滑动时间窗口 * 每次成功访问时,记录访问时间点 * 每次清理N分钟之前的访问时间点 * 对访问次数进行计数,判断是否超过次数 * @param $minute * @param $count * @param $times * @return bool */ function timeWindow($minute, $count, &$times){ $now = time(); $point = $now - $minute * 60;//从当前时间往前推N分钟的时间点 foreach($times as $key => $item){ if($item < $point) unset($times[$key]); //把N分钟之前的访问清理掉 } if(count($times) <= $count){ $times[] = $now; //成功时,记录本次访问时间点 return true; } return false; }