Bläddra i källkod

Change ban cache structure

Visman 5 år sedan
förälder
incheckning
ec9334550d
4 ändrade filer med 151 tillägg och 55 borttagningar
  1. 40 25
      app/Models/BanList/Check.php
  2. 36 19
      app/Models/BanList/IsBanned.php
  3. 34 10
      app/Models/BanList/Load.php
  4. 41 1
      app/Models/BanList/Model.php

+ 40 - 25
app/Models/BanList/Check.php

@@ -23,45 +23,60 @@ class Check extends Method
         }
 
         // удаление просроченных банов
-        $now = \time();
-        $ids = [];
-        foreach ($this->model->otherList as $id => $row) {
-            if (null !== $row['expire'] && $row['expire'] < $now) {
-                $ids[] = $id;
+        if (! empty($this->model->banList)) { // ???? зачем при каждом запуске проверять просроченность?
+            $ids = [];
+            $now = \time();
+
+            foreach ($this->model->banList as $id => $row) {
+                if (null !== $row['expire'] && $row['expire'] < $now) {
+                    $ids[] = $id;
+                }
+            }
+
+            if (! empty($ids)) {
+                $this->model->delete($ids);
             }
-        }
-        if (! empty($ids)) {
-            $this->model->delete($ids);
         }
 
         // проверка гостя
         if ($user->isGuest) {
-            $ip = $this->model->trimToNull($user->ip);
-            if (null === $ip) {
-                return false; //????
-            }
-            $add = \strpos($ip, ':') === false ? '.' : ':'; //????
-            $ip .= $add;
-            foreach ($this->model->ipList as $addr => $id) {
-                $addr .= $add;
-                if (\substr($ip, 0, \strlen($addr)) == $addr) {
-                    if (isset($this->model->otherList[$id])) {
-                        $user->__banInfo = $this->model->otherList[$id];
+            if (! empty($this->model->ipList)) {
+                $ip = $this->model->trimToNull($user->ip);
+
+                if (null !== $ip) {
+                    $list    = $this->model->ipList;
+                    $letters = \str_split($this->model->ip2hex($ip));
+
+                    foreach ($letters as $letter) {
+                        if (! isset($list[$letter])) {
+                            break;
+                        } elseif (\is_array($list[$letter])) {
+                            $list = $list[$letter];
+                        } else {
+                            $id = $list[$letter];
+
+                            if (isset($this->model->banList[$id])) {
+                                $user->__banInfo = $this->model->banList[$id];
+                            }
+
+                            return true;
+                        }
                     }
-                    return true;
                 }
             }
         // проверка пользователя
         } else {
-            $name = $this->model->trimToNull($user->username, true);
-            if (isset($this->model->userList[$name])) {
-                $id = $this->model->userList[$name];
-                if (isset($this->model->otherList[$id])) {
-                    $user->__banInfo = $this->model->otherList[$id];
+            $id = $this->model->isBanned($user);
+
+            if ($id > 0) {
+                if (isset($this->model->banList[$id])) {
+                    $user->__banInfo = $this->model->banList[$id];
                 }
+
                 return true;
             }
         }
+
         return false;
     }
 }

+ 36 - 19
app/Models/BanList/IsBanned.php

@@ -17,31 +17,48 @@ class IsBanned extends Method
     public function isBanned(User $user)
     {
         $name  = $this->model->trimToNull($user->username, true);
+        // бан имени пользователя
         if (null !== $name && isset($this->model->userList[$name])) {
-            return 1;
+            return $this->model->userList[$name];
         }
-        $email = $this->model->trimToNull($user->email);
-        if (null !== $email) {
-            foreach ($this->model->otherList as $cur) {
-                if (null === $cur['email']) {
-                    continue;
-                } elseif ($email == $cur['email']) {
-                    return 2;
-                } elseif (false === \strpos($cur['email'], '@')) {
-                    $len = \strlen($cur['email']);
-                    if ('.' === $cur['email'][0]) {
-                        if (\substr($email, -$len) === $cur['email']) {
-                            return 2;
+        // бан email
+        if ($user->isGuest && ! empty($this->model->emailList) && $user->email && $user->email_normal) { // ????
+            $email = $this->model->trimToNull($user->email_normal);
+            $stage = 0;
+
+            do {
+                if (isset($this->model->emailList[$email])) {
+                    return $this->model->emailList[$email];
+                }
+
+                switch ($stage) {                               // "super@user"@example.com
+                    case 0:
+                        $pos = \strrpos($email, '@');
+
+                        if (false !== $pos) {
+                            $email = \substr($email, $pos + 1); // -> example.com
+                            break;
                         }
-                    } else {
-                        $tmp = \substr($email, -1-$len);
-                        if ($tmp === '.' . $cur['email'] || $tmp === '@' . $cur['email']) {
-                            return 2;
+
+                        ++$stage;
+                    case 1:
+                        $email = '.' . $email;                  // -> .example.com
+                        $pos = true;
+                        break;
+                    default:
+                        $pos = \strpos($email, '.', 1);
+
+                        if (false !== $pos) {
+                            $email = \substr($email, $pos);     // -> .com
                         }
-                    }
+
+                        break;
                 }
-            }
+
+                ++$stage;
+            } while (false !== $pos);
         }
+
         return 0;
     }
 }

+ 34 - 10
app/Models/BanList/Load.php

@@ -15,8 +15,11 @@ class Load extends Method
     public function load()
     {
         $userList  = [];
+        $emailList = [];
         $ipList    = [];
-        $otherList = [];
+        $banList   = [];
+
+
         $stmt = $this->c->DB->query('SELECT b.id, b.username, b.ip, b.email, b.message, b.expire FROM ::bans AS b');
         while ($row = $stmt->fetch()) {
             $name = $this->model->trimToNull($row['username'], true);
@@ -24,35 +27,56 @@ class Load extends Method
                 $userList[$name] = $row['id'];
             }
 
+            $email   = $this->model->trimToNull($row['email']);
+            if (null !== $email) {
+                $email = $this->c->NormEmail->normalize($email);
+                $emailList[$email] = $row['id']; // ???? TODO если домен забанен, то email не добавлять
+            }
+
             $ips = $this->model->trimToNull($row['ip']);
             if (null !== $ips) {
                 foreach (\explode(' ', $ips) as $ip) {
-                    $ip = \trim($ip);
-                    if ('' != $ip) {
-                        $ipList[$ip] = $row['id'];
+                    $list    = &$ipList;
+                    $letters = \str_split($this->model->ip2hex($ip));
+                    $count   = \count($letters);
+
+                    foreach ($letters as $letter) {
+                        if (--$count) {
+                            if (! isset($list[$letter])) {
+                                $list[$letter] = [];
+                            } elseif (! \is_array($list[$letter])) {
+                                break;
+                            }
+                            $list = &$list[$letter];
+                        } else {
+                            $list[$letter] = $row['id']; // ???? может не перезаписывать предыдущий бан?
+                        }
                     }
+
+                    unset($list);
                 }
             }
 
-            $email   = $this->model->trimToNull($row['email']);
             $message = $this->model->trimToNull($row['message']);
             $expire  = empty($row['expire']) ? null : $row['expire'];
-            if (! isset($email) && ! isset($message) && ! isset($expire)) {
+
+            if (null === $message && null === $expire) {
                 continue;
             }
 
-            $otherList[$row['id']] = [
-                'email'    => $email,
+            $banList[$row['id']] = [
                 'message'  => $message,
                 'expire'   => $expire,
             ];
         }
-        $this->model->otherList = $otherList;
+        $this->model->banList   = $banList;
         $this->model->userList  = $userList;
+        $this->model->emailList = $emailList;
         $this->model->ipList    = $ipList;
         $this->c->Cache->set('banlist', [
-            'otherList' => $otherList,
+            'banList'   => $banList,
             'userList'  => $userList,
+            'emailList' => $emailList,
             'ipList'    => $ipList,
         ]);
         return $this->model;

+ 41 - 1
app/Models/BanList/Model.php

@@ -15,12 +15,19 @@ class Model extends ParentModel
     {
         if ($this->c->Cache->has('banlist')) {
             $list = $this->c->Cache->get('banlist');
-            $this->otherList = $list['otherList'];
+        } else {
+            $list = null;
+        }
+
+        if (isset($list['banList'], $list['userList'], $list['emailList'], $list['ipList'])) {
+            $this->banList   = $list['banList'];
             $this->userList  = $list['userList'];
+            $this->emailList = $list['emailList'];
             $this->ipList    = $list['ipList'];
         } else {
             $this->load();
         }
+
         return $this;
     }
 
@@ -43,4 +50,37 @@ class Model extends ParentModel
             return $val;
         }
     }
+
+    /**
+     * Переводит ip/ip-подсеть в hex представление
+     *
+     * @param string $ip
+     *
+     * @return string
+     */
+    public function ip2hex($ip)
+    {
+        $bin = \inet_pton($ip);
+
+        if (false === $bin) {
+            if (\preg_match('%[:a-fA-F]|\d{4}%', $ip)) {
+                $result = '';
+                // 0000-ffff
+                foreach (\explode(':', $ip) as $cur) {
+                    $result .= \substr('0000' . \strtolower($cur), -4);
+                }
+            } else {
+                $result = '-';
+                // 00-ff
+                foreach (\explode('.', $ip) as $cur) {
+                    $result .= \sprintf('%02x', $cur);
+                }
+            }
+
+            return $result;
+        } else {
+            // The hyphen is needed for the joint sorting ipv4 and ipv6
+            return (isset($bin[4]) ? '' : '-') . \bin2hex($bin);
+        }
+    }
 }