ShouldThrottle.php 3.0 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147
  1. <?php
  2. namespace Yansongda\Supports\Traits;
  3. use Predis\Client;
  4. /**
  5. * Trait ShouldThrottle.
  6. *
  7. * @property Client $redis
  8. */
  9. trait ShouldThrottle
  10. {
  11. /**
  12. * _throttle.
  13. *
  14. * @var array
  15. */
  16. protected $_throttle = [
  17. 'limit' => 60,
  18. 'period' => 60,
  19. 'count' => 0,
  20. 'reset_time' => 0,
  21. ];
  22. /**
  23. * isThrottled.
  24. *
  25. * @author yansongda <me@yansongda.cn>
  26. *
  27. * @param string $key
  28. * @param int $limit
  29. * @param int $period
  30. * @param bool $auto_add
  31. *
  32. * @return bool
  33. */
  34. public function isThrottled($key, $limit = 60, $period = 60, $auto_add = false)
  35. {
  36. if (-1 === $limit) {
  37. return false;
  38. }
  39. $now = microtime(true) * 1000;
  40. $this->redis->zremrangebyscore($key, 0, $now - $period * 1000);
  41. $this->_throttle = [
  42. 'limit' => $limit,
  43. 'period' => $period,
  44. 'count' => $this->getThrottleCounts($key, $period),
  45. 'reset_time' => $this->getThrottleResetTime($key, $now),
  46. ];
  47. if ($this->_throttle['count'] < $limit) {
  48. if ($auto_add) {
  49. $this->throttleAdd($key, $period);
  50. }
  51. return false;
  52. }
  53. return true;
  54. }
  55. /**
  56. * 限流 + 1.
  57. *
  58. * @author yansongda <me@yansongda.cn>
  59. *
  60. * @param string $key
  61. * @param int $period
  62. */
  63. public function throttleAdd($key, $period = 60)
  64. {
  65. $now = microtime(true) * 1000;
  66. $this->redis->zadd($key, [$now => $now]);
  67. $this->redis->expire($key, $period * 2);
  68. }
  69. /**
  70. * getResetTime.
  71. *
  72. * @author yansongda <me@yansongda.cn>
  73. *
  74. * @param $key
  75. * @param $now
  76. *
  77. * @return int
  78. */
  79. public function getThrottleResetTime($key, $now)
  80. {
  81. $data = $this->redis->zrangebyscore(
  82. $key,
  83. $now - $this->_throttle['period'] * 1000,
  84. $now,
  85. ['limit' => [0, 1]]
  86. );
  87. if (0 === count($data)) {
  88. return $this->_throttle['reset_time'] = time() + $this->_throttle['period'];
  89. }
  90. return intval($data[0] / 1000) + $this->_throttle['period'];
  91. }
  92. /**
  93. * 获取限流相关信息.
  94. *
  95. * @author yansongda <me@yansongda.cn>
  96. *
  97. * @param string|null $key
  98. * @param mixed|null $default
  99. *
  100. * @return array|null
  101. */
  102. public function getThrottleInfo($key = null, $default = null)
  103. {
  104. if (is_null($key)) {
  105. return $this->_throttle;
  106. }
  107. if (isset($this->_throttle[$key])) {
  108. return $this->_throttle[$key];
  109. }
  110. return $default;
  111. }
  112. /**
  113. * 获取已使用次数.
  114. *
  115. * @author yansongda <me@yansongda.cn>
  116. *
  117. * @param string $key
  118. * @param int $period
  119. *
  120. * @return string
  121. */
  122. public function getThrottleCounts($key, $period = 60)
  123. {
  124. $now = microtime(true) * 1000;
  125. return $this->redis->zcount($key, $now - $period * 1000, $now);
  126. }
  127. }