Redis缓存防止网站cc攻击
介绍
前面写过一片利用session防止网站cc攻击的博客,这里换另一种方法,利用redis自增
来防止网站cc攻击。
废话不多说,上代码
简单redis操作类
<?php
namespace App\model\cache\redis;
class redis
{
private static $RedisObj;
private $host = '127.0.0.1';
private $port = '6379';
private $timeout = 0;
private $expire = 0;
private $redis;
private $ifscarlar = "niushao";
/**
* 构造函数,判断redis安装情况,实例化Redis对象,并且连接
* @access private
* @param string $host redis主机
* @param string $port redis端口
*/
private function __construct($host,$port)
{
if(!extension_loaded('redis')){
die("<h1 style='text-align:center'>没有安装redis扩展,请安装……</h1>");
}
$host && $this->host = $host;
$port && $this->port = $port;
//连接redis
$this->redis = new \Redis();
$this->redis->connect($this->host,$this->port) or die('<h1 style="text-align:center">redis连接失败,请检查端口</h1>');
}
/**
* 单例模式获取对象函数
* @access private
* @param string $host redis主机
* @param string $port redis端口
* @return object
*/
public static function getInstance($host,$port)
{
if(self::$RedisObj == null){
self::$RedisObj = new redis($host,$port);
}
return self::$RedisObj;
}
/**
* 写入缓存
* @access public
* @param string $key 缓存变量名
* @param mixed $val 存储数据
* @param integer $expire 有效时间(秒)
* @return boolean
*/
public function set($key,$val,$expire = null)
{
if(is_null($expire)){
$expire = $this->expire;
}
//如果是时间对象的话,转换为友好时间格式类型
if($expire instanceof \DateTime){
$expire = $expire->getTimestamp() - time();
}
//判断是标量否,不是则序列化。
if(!is_scalar($val)){
$val = $this->ifscarlar.':'.serialize($val);
}
if($expire){
$res = $this->redis->setex($key,$expire,$val);
}else{
$res = $this->redis->set($key,$val);
}
return $res;
}
/**
* 读取缓存
* @access public
* @param string $key 缓存变量名
* @return mixed | bool
*/
public function get($key)
{
$val = $this->redis->get($key);
//注意这里为什么要这么做
if(strpos($val,$this->ifscarlar) === false){
//匹配不上,表示是标量,不用序列化直接输出
return $val;
}else{
//匹配成功,反序列化之后输出
$val = unserialize(substr($val,strlen($this->ifscarlar)+1));
return $val;
}
}
/**
* 判断缓存
* @access public
* @param string $key 缓存变量名
* @return bool
*/
public function has($key)
{
$res = $this->redis->get($key)?true:false;
return $res;
}
/**
* 自增缓存(针对数值缓存)
* @access public
* @param string $key 缓存变量名
* @param int $step 步长
* @return int
*/
public function inc($key,$step = 1)
{
if(!is_numeric($this->get($key))){
die('<h1 style="text-align:center">此$key不满足条件,无法自减</h1>');
}
$res = $this->redis->incrby($key,$step);
return $res;
}
/**
* 自减缓存(针对数值缓存)
* @access public
* @param string $key 缓存变量名
* @param int $step 步长
* @return int
*/
public function dec($key,$step = 1)
{
if(!is_numeric($this->get($key))){
die('<h1 style="text-align:center">此$key不满足条件,无法自减</h1>');
}
$res = $this->redis->decrby($key,$step);
return $res;
}
/**
* 删除缓存
* @access public
* @param string $key 缓存变量名
* @return boolean
*/
public function rm($key)
{
$res = $this->redis->delete($key);
return $res;
}
/**
* 清除缓存
* @access public
* @return boolean
*/
public function clear()
{
$res = $this->redis->flushDB();
return $res;
}
}
获取客户端ip
见博客 http://blog.csdn.net/siukong_ngau/article/details/78664528
核心代码
<?php
require_once __DIR__."/require_files.php";
//实例化redis操作类
$RedisObj = App\model\cache\redis\redis::getInstance('127.0.0.1','6379');
//获取客户端ip
$ip = real_ip();
//构造存入redis条件
$handle = 1;
$key = md5('visitor:'.$ip);
$time = 1;
if(!$RedisObj->has($key)){
$RedisObj->set($key,$handle,$time);
}
$inc_num = $RedisObj->inc($key);
if($inc_num>5){
die('点击太过频繁,请稍后');
}
注意:实际面向对象生产环境中建议将此类封装成方法,引入构造方法中,可防止整站遭受过快刷新的cc攻击
github地址:https://github.com/NIUSG/Cache