zoukankan      html  css  js  c++  java
  • [PHP] 频率限制类

    比如要实现

    单个ip限制60秒1次
    单个关键字,比如手机号,限制60秒1次,3600秒10次

    <?php
    class Sina_Mail_WebAntispam {
    
        const PREFIX_WHITELIST = 'w:';
        const PREFIX_KILL = 'k:';
        const PREFIX_VERIFYCODE = 'c:';
        const PREFIX_VERIFIED = 'v:';
        const STATUS_UPDATE = '[U]';
    
        private $mc = null;
        private $config = null;
        private $whitelist = array();
        private $keyPrefix = '';
        private $intervals = array();
        private $updates = array();
        private $status = array();
    
        public function __construct($mc, $config) {
            $this->mc = $mc;
            $this->config = $config;
            if (isset($this->config->prefix)) {
                $this->keyPrefix = $this->config->prefix;
            }
            if (isset($this->config->whitelistKey)) {
                $wls = $this->mc->get($this->config->whitelistKey);
                if (!empty($wls)) {
                    $this->whitelist = & $wls;
                }
            }
        }
    
        public function setWhitelist(&$whitelist) {
            $this->whitelist = & $whitelist;
        }
        /*验证限制规则*/
        public function check($ip = null, $key = null) {
            if (!$ip && !$key) {
                return false;
            }
    
            if ($key) {
                if (!is_array($key)) {
                    $keys = array($key);
                } else {
                    $keys = $key;
                }
            }
    
            // first filter by whitelist
            if (!empty($this->whitelist)) {
                if ($ip && $this->filterByWhitelist($ip, 'ip')) {
                    $this->status[self::PREFIX_WHITELIST . $ip] = 1;
                    return true;
                }
                if ($keys) {
                    foreach ($keys as $key) {
                        if ($this->filterByWhitelist($key, 'key')) {
                            $this->status[self::PREFIX_WHITELIST . $key] = 1;
                            return true;
                        }
                    }
                }
            }
    
            if ($ip) {
                $ip = $this->keyPrefix . $ip;
            }
    
            // second, check verified ok
            if (!empty($this->config->verified)) {
                if ($ip && $this->mc->get(self::PREFIX_VERIFIED . $ip)) {
                    $this->status[self::PREFIX_VERIFIED . $ip] = 1;
                    return true;
                }
                if ($keys) {
                    foreach ($keys as $key) {
                        $verifiedKey = self::PREFIX_VERIFIED . $this->keyPrefix . $key;
                        if ($this->mc->get($verifiedKey)) {
                            $this->status[$verifiedKey] = 1;
                            return true;
                        }
                    }
                }
            }
    
            $kos = !empty($this->config->kill);
            // check killed
            if ($kos) {
                if ($ip && $this->mc->get(self::PREFIX_KILL . $ip)) {
                    $this->status[self::PREFIX_KILL . $ip] = 1;
                    return false;
                }
                if ($keys) {
                    foreach ($keys as $key) {
                        $killKey = self::PREFIX_KILL . $this->keyPrefix . $key;
                        if ($this->mc->get($killKey)) {
                            $this->status[$killKey] = 1;
                            return false;
                        }
                    }
                }
            }
    
            // check ip rule
            if ($ip && isset($this->config->ip)) {
                if (!$this->checkRule($ip, $this->config->ip)) {
                    if ($kos && $this->mc->set(self::PREFIX_KILL . $ip, 1, intval($this->config->kill))) {
                        $this->status[self::PREFIX_KILL . $ip] = 1;
                    }
                    return false;
                }
            }
    
            // check keys rule
            if ($keys && isset($this->config->key)) {
                foreach ($keys as $key) {
                    if (!$this->checkRule($this->keyPrefix . $key, $this->config->key)) {
                        $killKey = self::PREFIX_KILL . $this->keyPrefix . $key;
                        if ($kos && $this->mc->set($killKey, 1, intval($this->config->kill))) {
                            $this->status[$killKey] = 1;
                        }
                        return false;
                    }
                }
            }
    
            return true;
        }
        /*更新限制规则*/
        public function update($c = 1, $ip = null, $key = null) {
            if (is_null($ip) && is_null($key)) {
                if (!empty($this->updates)) {
                    foreach ($this->updates as $k => $v) {
                        if (!$v && isset($this->intervals[$k])) {
                            if ($this->mc->add($k, $c, false,$this->intervals[$k])) {
                                $this->status[self::STATUS_UPDATE . $k] = $c;
                                continue;
                            }
                        }
                        $r = $this->mc->increment($k, $c);
                        $this->status[self::STATUS_UPDATE . $k] = $r;
                    }
                }
            } else {
                if (!is_null($ip) && isset($this->config->ip)) {
                    $rule = $this->config->ip;
                    foreach ($rule as $interval => $limit) {
                        $k = $this->keyPrefix . $ip . '_' . $interval;
                        if ($this->mc->add($k, $c,false,$interval)) {
                            $this->status[self::STATUS_UPDATE . $k] = true;
                            continue;
                        }
                        $r = $this->mc->increment($k, $c);
                        $this->status[self::STATUS_UPDATE . $k] = $r;
                    }
                }
                if (!is_null($key) && isset($this->config->key)) {
                    $rule = $this->config->key;
                    if (!is_array($key)) {
                        $keys = array($key);
                    } else {
                        $keys = $key;
                    }
                    foreach ($keys as $key) {
                        foreach ($rule as $interval => $limit) {
                            $k = $this->keyPrefix . $key . '_' . $interval;
                            if ($this->mc->add($k, $c,false,$interval)) {
                                $this->status[self::STATUS_UPDATE . $k] = true;
                                continue;
                            }
                            $r = $this->mc->increment($k, $c);
                            $this->status[self::STATUS_UPDATE . $k] = $r;
                        }
                    }
                }
            }
        }
    
        public function checkVerifyCode($key, $code) {
            $servcode = $this->mc->get(self::PREFIX_VERIFYCODE . $this->keyPrefix . $key);
            if (strcasecmp($servcode, $code) == 0) {
                $verified = intval($this->config->verified);
                if ($verified > 0) {
                    $r = $this->mc->set(self::PREFIX_VERIFIED . $this->keyPrefix . $key, 1, false, $verified);
                } else {
                    $r = true;
                }
                if ($r) {
                    $this->mc->delete(self::PREFIX_VERIFYCODE . $this->keyPrefix . $key);
                }
                return $r;
            }
            return false;
        }
    
        public function isVerified($key) {
            $r = $this->mc->get(self::PREFIX_VERIFIED . $this->keyPrefix . $key);
            if (!empty($r)) {
                return true;
            } else {
                return false;
            }
        }
    
        public function setVerifyCode($key, $code) {
            $verifytime = intval($this->config->verifytime);
            if ($verifytime < 1) {
                return false;
            }
            return $this->mc->set(self::PREFIX_VERIFYCODE . $this->keyPrefix . $key, $code, false, $verifytime);
        }
    
        public function getStatus() {
            return $this->status;
        }
    
        private function filterByWhitelist($value, $key) {
    //        if (empty($this->whitelist[$key])) {
    //            return false;
    //        }
    //        $ls = & $this->whitelist[$key];
            $ls = & $this->whitelist;
            foreach ($ls as $i) {
                if ($i[strlen($i) - 1] == '.') { // ip segment
                    if (strpos($value, $i) === 0) {
                        return true;
                    }
                } else {
                    if (strcmp($i, $value) === 0) {
                        return true;
                    }
                }
            }
            return false;
        }
    
        private function checkRule($key, $rule) {
            $flag = true;
            if (!empty($rule)) {
                foreach ($rule as $interval => $limit) {
                    $k = $key . '_' . $interval;
                    $c = $this->mc->get($k);
                    if (!$c) {
                        $this->updates[$k] = 0;
                        $this->intervals[$k] = $interval;
                        $this->status[$k] = 0;
                    } else {
                        $this->updates[$k] = $c;
                        $this->status[$k] = $c;
                        if ($c >= $limit) {
                            $flag = false;
                        }
                    }
                }
            }
            return $flag;
        }
    
        public static function getInstance($conf) {
            $mc = new Memcache();
            $mc->connect("115.159.28.112");
            $conf=json_decode(json_encode($conf));
            return new self($mc, $conf);
        }
    
    }
    /*
    单个ip限制60秒1次
    单个关键字,比如手机号,限制60秒1次,3600秒10次
    */
    $conf=array(
                'prefix' => 'selfservice:',
                'key' => array(60 => 1,3600=>10),
                'ip' => array(60 => 1),
            );
    $spam=Sina_Mail_WebAntispam::getInstance($conf);
    if(!$spam->check('127.25.12.123',17610725730)){
    	echo "limit...";
    	exit;
    }
    
    //更新频率限制
    $spam->update();
    

      

     memache中最终的存储key

  • 相关阅读:
    Mybatis里面的一对多,一对一查询
    Mybatis简单数据库查询
    tree的使用
    datagrid里面的实现分页功能
    web去掉浏览器自带默认样式
    C#邮件发送
    如何选择正确的标签?
    Table表格的一些操作
    SQL常用分页
    easyui-window
  • 原文地址:https://www.cnblogs.com/taoshihan/p/10610036.html
Copyright © 2011-2022 走看看