BlacklistService.php 5.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: wanggb
  5. * Date: 2018/11/22
  6. * Time: 19:57
  7. */
  8. namespace app\common\service;
  9. use app\common\constants\DomainBlackList;
  10. use app\common\library\Redis;
  11. use app\common\model\Blacklist;
  12. use app\main\service\UrlService;
  13. use think\Log;
  14. class BlacklistService
  15. {
  16. const ALLDOMAIN= 'alldomain';
  17. const DOMAINBYPARAM= 'domainbyparam';
  18. const DOMAINBYPATH= 'domainbypath';
  19. /**
  20. * @var BlacklistService
  21. */
  22. private static $self;
  23. /**
  24. * @var \Redis
  25. */
  26. protected $redis = null;
  27. protected $domain = null;
  28. protected $path = null;
  29. protected $param = null;
  30. /**
  31. * @return BlacklistService
  32. */
  33. public static function instance()
  34. {
  35. if(self::$self == NULL){
  36. self::$self = new self();
  37. }
  38. return self::$self;
  39. }
  40. /**
  41. * 校验域名,如果访问的域名在黑名单列表中,返回404
  42. * @param $request
  43. */
  44. public function checkDomain(&$request)
  45. {
  46. $this->redis = Redis::instance();
  47. //$this->domain = $request->domain();
  48. $this->domain = UrlService::instance()->getUnlimitDomainOriginWxUrl()->data;
  49. $this->path = $request->path();
  50. $this->param = $request->param();
  51. # redis_key => FFSN:wx7610e3344bdea6f6.dev.kpread.com
  52. $host_redis_key = DomainBlackList::REDISPREFIX . $this->formatDomain($this->domain);
  53. $redis_rules = $this->redis->hGetAll($host_redis_key);
  54. Log::info('domain black rules:' . json_encode($redis_rules, JSON_UNESCAPED_UNICODE));
  55. $result = false;
  56. if($redis_rules){
  57. foreach ($redis_rules as $rule => $item_type){
  58. if($item_type == DomainBlackList::LOCKALLDOMAIN){
  59. if($rule == $this->formatDomain($this->domain)){
  60. $result = true;
  61. break;
  62. }
  63. } elseif($item_type == DomainBlackList::LOCKDOMAINBYPARAM) {
  64. parse_str($rule, $param_arr);
  65. $param_flag = false;
  66. foreach ($param_arr as $arg_key => $arg_value) {
  67. if (array_key_exists($arg_key, $this->param) && $arg_value == $this->param[$arg_key]) {
  68. $param_flag = true;
  69. }
  70. }
  71. if ($param_flag) {
  72. $result = true;
  73. break;
  74. }
  75. }elseif($item_type == DomainBlackList::LOCKDOMAINBYPATH){
  76. if ($rule == $this->path) {
  77. $result = true;
  78. break;
  79. }
  80. }
  81. }
  82. }
  83. //$result = $this->validateRule();
  84. if ($result) {
  85. # 跳转到 404 页面
  86. http_response_code(404);
  87. header('HTTP/1.1 404 Not Found');
  88. $html = "<html><head><title>页面无法访问</title></head><body><h1 style='text-align: center; margin-top: 15%;'>页面走丢了!</h1></body></html>";
  89. echo $html;
  90. exit();
  91. }
  92. }
  93. /**
  94. * 进行规则校验,成功返回true;
  95. * @return bool|string
  96. */
  97. public function validateRule()
  98. {
  99. $rules = $this->getValidateRule();
  100. foreach ($rules as $key => $item) {
  101. foreach ($item as $k => $v) {
  102. if ($key == self::ALLDOMAIN) {
  103. # 仅校验 domain
  104. if ($this->domain == $v['domain']) {
  105. return true;
  106. break;
  107. }
  108. } elseif ($key == self::DOMAINBYPARAM) {
  109. if ($this->domain == $v['domain']) {
  110. parse_str($v['param'], $param_arr);
  111. $param_flag = false;
  112. foreach ($param_arr as $arg_key => $arg_value) {
  113. if (array_key_exists($arg_key, $this->param) && $arg_value == $this->param[$arg_key]) {
  114. $param_flag = true;
  115. }
  116. }
  117. if ($param_flag) {
  118. return true;
  119. break;
  120. }
  121. }
  122. } elseif ($key == self::DOMAINBYPATH) {
  123. # 仅校验 domain
  124. if ($this->path == $v['path']) {
  125. return true;
  126. break;
  127. }
  128. }
  129. }
  130. }
  131. }
  132. /**
  133. * 获取域名黑名单的校验规则
  134. * @return array
  135. * @throws \think\db\exception\DataNotFoundException
  136. * @throws \think\db\exception\ModelNotFoundException
  137. * @throws \think\exception\DbException
  138. */
  139. public function getValidateRule()
  140. {
  141. $blackListModel = new Blacklist();
  142. $black_roles = $blackListModel->where('status', '=', 'active')->order('type')->select();
  143. $black_group = [];
  144. if ($black_roles) {
  145. foreach ($black_roles as $k => $v) {
  146. if ($v['type'] == DomainBlackList::LOCKALLDOMAIN) {
  147. $black_group[self::ALLDOMAIN][] = $v;
  148. } elseif ($v['type'] == DomainBlackList::LOCKDOMAINBYPARAM) {
  149. $black_group[self::DOMAINBYPARAM][] = $v;
  150. } elseif ($v['type'] == DomainBlackList::LOCKDOMAINBYPATH) {
  151. $black_group[self::DOMAINBYPATH][] = $v;
  152. }
  153. }
  154. }
  155. return $black_group;
  156. }
  157. public function getRedisRules()
  158. {
  159. $this->redis = Redis::instance();
  160. $rules = $this->redis->hGetAll();
  161. }
  162. /**
  163. * @param $domain
  164. * @return mixed
  165. */
  166. public function formatDomain($domain)
  167. {
  168. $domain = str_replace("https:","http:",$domain);
  169. preg_match("/^(http:\/\/)?([^\/]+)/i", $domain, $matches);
  170. return $matches[2];
  171. }
  172. }