Zhu Jinhui преди 7 години
родител
ревизия
99e542a35b
променени са 2 файла, в които са добавени 126 реда и са изтрити 1 реда
  1. 21 1
      src/Cache/Redis.php
  2. 105 0
      src/Library/RateLimit.php

+ 21 - 1
src/Cache/Redis.php

@@ -50,7 +50,7 @@ class Redis implements Intf
     /**
      * 保存指定key的数据
      */
-    public function set($id, $data, array $policy = null)
+    public function hMset($id, $data, array $policy = null)
     {
         if (!isset($policy['life_time'])) $policy['life_time'] = $this->policy['life_time'];
         try {
@@ -63,6 +63,21 @@ class Redis implements Intf
         }
     }
 
+    /**
+     * 保存指定key的数据
+     */
+    public function set($id, $value, array $policy = null)
+    {
+        if (!isset($policy['life_time'])) $policy['life_time'] = $this->policy['life_time'];
+        try {
+            $this->redis->set($id, $value);
+            if (isset($policy['life_time']) && $policy['life_time'] > 0) {
+                $this->redis->setTimeout($id, $policy['life_time']);
+            }
+        } catch (\CredisException $e) {
+            throw new \Qii\Exceptions\Errors(\Qii::i(-1, $e->getMessage()), __LINE__);
+        }
+    }
     /**
      * 获取指定key的数据
      */
@@ -83,6 +98,11 @@ class Redis implements Intf
         }
         return null;
     }
+    
+    public function exists($id)
+    {
+        return $this->redis->exists($id);
+    }
 
     /**
      * 删除指定key的数据

+ 105 - 0
src/Library/RateLimit.php

@@ -0,0 +1,105 @@
+<?php
+namespace Qii\Library;
+
+class RateLimit
+{
+    /**
+     *
+     * @var string
+     */
+    public $name;
+    /**
+     *
+     * @var int
+     */
+    public $maxRequests;
+    /**
+     *
+     * @var int
+     */
+    public $period;
+    /**
+     *
+     * @var int
+     */
+    public $ttl;
+    /**
+     *
+     * @var Adapter
+     */
+    private $adapter;
+
+	public function __construct($name, $maxRequests, $period, $adapter)
+	{
+		$this->name = $name;
+		$this->maxRequests = $maxRequests;
+        $this->period = $period;
+        $this->ttl = $this->period;
+		$this->adapter = $adapter;
+	}
+
+	 /**
+     * Rate Limiting
+     * http://stackoverflow.com/a/668327/670662
+     * @param string $id
+     * @param float $use
+     * @return boolean
+     */
+    public function check($id, $use = 1.0)
+    {
+        $rate = $this->maxRequests / $this->period;
+        $tKey = $this->keyTime($id);
+        $aKey = $this->keyAllow($id);
+        if ($this->adapter->exists($tKey)) {
+            $cTime = time();
+            $timePassed = $cTime - $this->adapter->get($tKey);
+            $this->adapter->set($tKey, $cTime, ['life_time' => $this->ttl]);
+            $allow = $this->adapter->get($aKey);
+            $allow += $timePassed * $rate;
+            if ($allow > $this->maxRequests) {
+                $allow = $this->maxRequests;
+            }
+            if ($allow < $use) {
+                $this->adapter->set($aKey, $allow, ['life_time' => $this->ttl]);
+                return 0;
+            } else {
+                $this->adapter->set($aKey, $allow - $use, ['life_time' => $this->ttl]);
+                return (int) ceil($allow);
+            }
+        } else {
+            $this->adapter->set($tKey, time(), ['life_time' => $this->ttl]);
+            $this->adapter->set($aKey, $this->maxRequests - $use, ['life_time' => $this->ttl]);
+            return $this->maxRequests;
+        }
+    }
+
+    public function getAllow($id)
+    {
+        $this->check($id, 0.0);
+        $aKey = $this->keyAllow($id);
+        if (!$this->adapter->exists($aKey)) {
+            return $this->maxRequests;
+        } else {
+            return max(0, floor($this->adapter->get($aKey)));
+        }
+    }
+    /**
+     * Purge rate limit record for $id
+     * @param string $id
+     */
+    public function purge($id)
+    {
+        $this->adapter->del($this->keyTime($id));
+        $this->adapter->del($this->keyAllow($id));
+    }
+
+    public function keyTime($id)
+    {
+        return $this->name . ":" . $id . ":time";
+    }
+
+    public function keyAllow($id)
+    {
+        return $this->name . ":" . $id . ":allow";
+    }
+}