Dotclear

source: plugins/antispam/filters/class.dc.filter.ip.php @ 3874:ab8368569446

Revision 3874:ab8368569446, 9.6 KB checked in by franck <carnet.franck.paul@…>, 7 years ago (diff)

short notation for array (array() → [])

Line 
1<?php
2/**
3 * @brief antispam, a plugin for Dotclear 2
4 *
5 * @package Dotclear
6 * @subpackage Plugins
7 *
8 * @copyright Olivier Meunier & Association Dotclear
9 * @copyright GPL-2.0-only
10 */
11
12if (!defined('DC_RC_PATH')) {return;}
13
14class dcFilterIP extends dcSpamFilter
15{
16    public $name    = 'IP Filter';
17    public $has_gui = true;
18    public $help    = 'ip-filter';
19
20    private $con;
21    private $table;
22
23    public function __construct($core)
24    {
25        parent::__construct($core);
26        $this->con   = &$core->con;
27        $this->table = $core->prefix . 'spamrule';
28    }
29
30    protected function setInfo()
31    {
32        $this->description = __('IP Blacklist / Whitelist Filter');
33    }
34
35    public function getStatusMessage($status, $comment_id)
36    {
37        return sprintf(__('Filtered by %1$s with rule %2$s.'), $this->guiLink(), $status);
38    }
39
40    public function isSpam($type, $author, $email, $site, $ip, $content, $post_id, &$status)
41    {
42        if (!$ip) {
43            return;
44        }
45
46        # White list check
47        if ($this->checkIP($ip, 'white') !== false) {
48            return false;
49        }
50
51        # Black list check
52        if (($s = $this->checkIP($ip, 'black')) !== false) {
53            $status = $s;
54            return true;
55        }
56    }
57
58    public function gui($url)
59    {
60        global $default_tab;
61        $core = &$this->core;
62
63        # Set current type and tab
64        $ip_type = 'black';
65        if (!empty($_REQUEST['ip_type']) && $_REQUEST['ip_type'] == 'white') {
66            $ip_type = 'white';
67        }
68        $default_tab = 'tab_' . $ip_type;
69
70        # Add IP to list
71        if (!empty($_POST['addip'])) {
72            try
73            {
74                $global = !empty($_POST['globalip']) && $core->auth->isSuperAdmin();
75
76                $this->addIP($ip_type, $_POST['addip'], $global);
77                dcPage::addSuccessNotice(__('IP address has been successfully added.'));
78                http::redirect($url . '&ip_type=' . $ip_type);
79            } catch (Exception $e) {
80                $core->error->add($e->getMessage());
81            }
82        }
83
84        # Remove IP from list
85        if (!empty($_POST['delip']) && is_array($_POST['delip'])) {
86            try {
87                $this->removeRule($_POST['delip']);
88                dcPage::addSuccessNotice(__('IP addresses have been successfully removed.'));
89                http::redirect($url . '&ip_type=' . $ip_type);
90            } catch (Exception $e) {
91                $core->error->add($e->getMessage());
92            }
93        }
94
95        /* DISPLAY
96        ---------------------------------------------- */
97        $res = dcPage::notices();
98
99        $res .=
100        $this->displayForms($url, 'black', __('Blacklist')) .
101        $this->displayForms($url, 'white', __('Whitelist'));
102
103        return $res;
104    }
105
106    private function displayForms($url, $type, $title)
107    {
108        $core = &$this->core;
109
110        $res =
111        '<div class="multi-part" id="tab_' . $type . '" title="' . $title . '">' .
112
113        '<form action="' . html::escapeURL($url) . '" method="post" class="fieldset">' .
114
115        '<p>' .
116        form::hidden(['ip_type'], $type) .
117        '<label class="classic" for="addip_' . $type . '">' . __('Add an IP address: ') . '</label> ' .
118        form::field(['addip', 'addip_' . $type], 18, 255);
119        if ($core->auth->isSuperAdmin()) {
120            $res .= '<label class="classic" for="globalip_' . $type . '">' . form::checkbox(['globalip', 'globalip_' . $type], 1) . ' ' .
121            __('Global IP (used for all blogs)') . '</label> ';
122        }
123
124        $res .=
125        $core->formNonce() .
126        '</p>' .
127        '<p><input type="submit" value="' . __('Add') . '"/></p>' .
128            '</form>';
129
130        $rs = $this->getRules($type);
131
132        if ($rs->isEmpty()) {
133            $res .= '<p><strong>' . __('No IP address in list.') . '</strong></p>';
134        } else {
135            $res .=
136            '<form action="' . html::escapeURL($url) . '" method="post">' .
137            '<h3>' . __('IP list') . '</h3>' .
138                '<div class="antispam">';
139
140            $res_global = '';
141            $res_local  = '';
142            while ($rs->fetch()) {
143                $bits    = explode(':', $rs->rule_content);
144                $pattern = $bits[0];
145                $ip      = $bits[1];
146                $bitmask = $bits[2];
147
148                $disabled_ip = false;
149                $p_style     = '';
150                if (!$rs->blog_id) {
151                    $disabled_ip = !$core->auth->isSuperAdmin();
152                    $p_style .= ' global';
153                }
154
155                $item =
156                '<p class="' . $p_style . '"><label class="classic" for="' . $type . '-ip-' . $rs->rule_id . '">' .
157                form::checkbox(['delip[]', $type . '-ip-' . $rs->rule_id], $rs->rule_id,
158                    [
159                        'disabled' => $disabled_ip
160                    ]
161                ) . ' ' .
162                html::escapeHTML($pattern) .
163                    '</label></p>';
164
165                if ($rs->blog_id) {
166                    // local list
167                    if ($res_local == '') {
168                        $res_local = '<h4>' . __('Local IPs (used only for this blog)') . '</h4>';
169                    }
170                    $res_local .= $item;
171                } else {
172                    // global list
173                    if ($res_global == '') {
174                        $res_global = '<h4>' . __('Global IPs (used for all blogs)') . '</h4>';
175                    }
176                    $res_global .= $item;
177                }
178            }
179            $res .= $res_local . $res_global;
180
181            $res .=
182            '</div>' .
183            '<p><input class="submit delete" type="submit" value="' . __('Delete') . '"/>' .
184            $core->formNonce() .
185            form::hidden(['ip_type'], $type) .
186                '</p>' .
187                '</form>';
188        }
189
190        $res .= '</div>';
191
192        return $res;
193    }
194
195    private function ipmask($pattern, &$ip, &$mask)
196    {
197        $bits = explode('/', $pattern);
198
199        # Set IP
200        $bits[0] .= str_repeat(".0", 3 - substr_count($bits[0], "."));
201        $ip = ip2long($bits[0]);
202
203        if (!$ip || $ip == -1) {
204            throw new Exception('Invalid IP address');
205        }
206
207        # Set mask
208        if (!isset($bits[1])) {
209            $mask = -1;
210        } elseif (strpos($bits[1], '.')) {
211            $mask = ip2long($bits[1]);
212            if (!$mask) {
213                $mask = -1;
214            }
215        } else {
216            $mask = ~((1 << (32 - $bits[1])) - 1);
217        }
218    }
219
220    public function addIP($type, $pattern, $global)
221    {
222        $this->ipmask($pattern, $ip, $mask);
223        $pattern = long2ip($ip) . ($mask != -1 ? '/' . long2ip($mask) : '');
224        $content = $pattern . ':' . $ip . ':' . $mask;
225
226        $old = $this->getRuleCIDR($type, $global, $ip, $mask);
227        $cur = $this->con->openCursor($this->table);
228
229        if ($old->isEmpty()) {
230            $id = $this->con->select('SELECT MAX(rule_id) FROM ' . $this->table)->f(0) + 1;
231
232            $cur->rule_id      = $id;
233            $cur->rule_type    = (string) $type;
234            $cur->rule_content = (string) $content;
235
236            if ($global && $this->core->auth->isSuperAdmin()) {
237                $cur->blog_id = null;
238            } else {
239                $cur->blog_id = $this->core->blog->id;
240            }
241
242            $cur->insert();
243        } else {
244            $cur->rule_type    = (string) $type;
245            $cur->rule_content = (string) $content;
246            $cur->update('WHERE rule_id = ' . (integer) $old->rule_id);
247        }
248    }
249
250    private function getRules($type = 'all')
251    {
252        $strReq =
253        'SELECT rule_id, rule_type, blog_id, rule_content ' .
254        'FROM ' . $this->table . ' ' .
255        "WHERE rule_type = '" . $this->con->escape($type) . "' " .
256        "AND (blog_id = '" . $this->core->blog->id . "' OR blog_id IS NULL) " .
257            'ORDER BY blog_id ASC, rule_content ASC ';
258
259        return $this->con->select($strReq);
260    }
261
262    private function getRuleCIDR($type, $global, $ip, $mask)
263    {
264        $strReq =
265        'SELECT * FROM ' . $this->table . ' ' .
266        "WHERE rule_type = '" . $this->con->escape($type) . "' " .
267        "AND rule_content LIKE '%:" . (integer) $ip . ":" . (integer) $mask . "' " .
268            'AND blog_id ' . ($global ? 'IS NULL ' : "= '" . $this->core->blog->id . "' ");
269
270        return $this->con->select($strReq);
271    }
272
273    private function checkIP($cip, $type)
274    {
275        $core = &$this->core;
276
277        $strReq =
278        'SELECT DISTINCT(rule_content) ' .
279        'FROM ' . $this->table . ' ' .
280        "WHERE rule_type = '" . $this->con->escape($type) . "' " .
281        "AND (blog_id = '" . $this->core->blog->id . "' OR blog_id IS NULL) " .
282            'ORDER BY rule_content ASC ';
283
284        $rs = $this->con->select($strReq);
285        while ($rs->fetch()) {
286            list($pattern, $ip, $mask) = explode(':', $rs->rule_content);
287            if ((ip2long($cip) & (integer) $mask) == ((integer) $ip & (integer) $mask)) {
288                return $pattern;
289            }
290        }
291        return false;
292    }
293
294    private function removeRule($ids)
295    {
296        $strReq = 'DELETE FROM ' . $this->table . ' ';
297
298        if (is_array($ids)) {
299            foreach ($ids as $i => $v) {
300                $ids[$i] = (integer) $v;
301            }
302            $strReq .= 'WHERE rule_id IN (' . implode(',', $ids) . ') ';
303        } else {
304            $ids = (integer) $ids;
305            $strReq .= 'WHERE rule_id = ' . $ids . ' ';
306        }
307
308        if (!$this->core->auth->isSuperAdmin()) {
309            $strReq .= "AND blog_id = '" . $this->core->blog->id . "' ";
310        }
311
312        $this->con->execute($strReq);
313    }
314}
Note: See TracBrowser for help on using the repository browser.

Sites map