SpamBlocker::allow()   A
last analyzed

Complexity

Conditions 2
Paths 2

Size

Total Lines 8
Code Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 4
CRAP Score 2

Importance

Changes 0
Metric Value
c 0
b 0
f 0
dl 0
loc 8
ccs 4
cts 4
cp 1
rs 9.4285
cc 2
eloc 4
nc 2
nop 1
crap 2
1
<?php namespace Arcanedev\SpamBlocker;
2
3
use Arcanedev\SpamBlocker\Contracts\SpamBlocker as SpamBlockerContract;
4
use Arcanedev\SpamBlocker\Entities\SpammerCollection;
5
use Closure;
6
use Illuminate\Support\Arr;
7
8
/**
9
 * Class     SpamBlocker
10
 *
11
 * @package  Arcanedev\SpamBlocker
12
 * @author   ARCANEDEV <[email protected]>
13
 */
14
class SpamBlocker implements SpamBlockerContract
15
{
16
    /* -----------------------------------------------------------------
17
     |  Properties
18
     | -----------------------------------------------------------------
19
     */
20
21
    /**
22
     * The spammers source path.
23
     *
24
     * @var string|null
25
     */
26
    protected $source;
27
28
    /**
29
     * The included spammers.
30
     *
31
     * @var array
32
     */
33
    protected $includes = [];
34
35
    /**
36
     * The excluded spammers.
37
     *
38
     * @var array
39
     */
40
    protected $excludes = [];
41
42
    /**
43
     * The spammers collection.
44
     *
45
     * @var \Arcanedev\SpamBlocker\Entities\SpammerCollection
46
     */
47
    protected $spammers;
48
49
    /**
50
     * Cache key.
51
     *
52
     * @var  string
53
     */
54
    protected $cacheKey;
55
56
    /**
57
     * Cache expiration duration.
58
     *
59
     * @var int
60
     */
61
    protected $cacheExpires;
62
63
    /* -----------------------------------------------------------------
64
     |  Constructor
65
     | -----------------------------------------------------------------
66
     */
67
68
    /**
69
     * SpamBlocker constructor.
70
     *
71
     * @param  array  $config
72
     */
73 81
    public function __construct(array $config)
74
    {
75 81
        $this->setSource(Arr::get($config, 'source', null));
76 81
        $this->setIncludes(Arr::get($config, 'include', []));
77 81
        $this->setExcludes(Arr::get($config, 'exclude', []));
78 81
        $this->cacheKey     = Arr::get($config, 'cache.key', 'arcanedev.spammers');
79 81
        $this->cacheExpires = Arr::get($config, 'cache.expires', 24 * 60);
80
81 81
        $this->load();
82 81
    }
83
84
    /* -----------------------------------------------------------------
85
     |  Getters & Setters
86
     | -----------------------------------------------------------------
87
     */
88
89
    /**
90
     * Get the loaded spammers.
91
     *
92
     * @return \Arcanedev\SpamBlocker\Entities\SpammerCollection
93
     */
94 51
    public function spammers()
95
    {
96 51
        return $this->spammers;
97
    }
98
99
    /**
100
     * Get the spammer source file.
101
     *
102
     * @return string|null
103
     */
104 6
    public function getSource()
105
    {
106 6
        return $this->source;
107
    }
108
109
    /**
110
     * Set the source path.
111
     *
112
     * @param  string  $source
113
     *
114
     * @return self
115
     */
116 81
    public function setSource($source)
117
    {
118 81
        if ( ! empty($source)) {
119 81
            $this->source = $source;
120
        }
121
122 81
        return $this;
123
    }
124
125
    /**
126
     * Get the included spammers.
127
     *
128
     * @return array
129
     */
130 12
    public function getIncludes()
131
    {
132 12
        return $this->includes;
133
    }
134
135
    /**
136
     * Set the included spammers.
137
     *
138
     * @param  array  $includes
139
     *
140
     * @return self
141
     */
142 81
    public function setIncludes(array $includes)
143
    {
144 81
        $this->includes = $includes;
145
146 81
        return $this;
147
    }
148
149
    /**
150
     * Get the excluded spammers.
151
     *
152
     * @return array
153
     */
154 12
    public function getExcludes()
155
    {
156 12
        return $this->excludes;
157
    }
158
159
    /**
160
     * Set the excluded spammers.
161
     *
162
     * @param  array  $excludes
163
     *
164
     * @return self
165
     */
166 81
    public function setExcludes(array $excludes)
167
    {
168 81
        $this->excludes = $excludes;
169
170 81
        return $this;
171
    }
172
173
    /* -----------------------------------------------------------------
174
     |  Main Methods
175
     | -----------------------------------------------------------------
176
     */
177
178
    /**
179
     * Load spammers.
180
     *
181
     * @return self
182
     */
183 81
    public function load()
184
    {
185 81
        $this->checkSource();
186
187 81
        $this->spammers = $this->cacheSpammers(function () {
188 81
            return SpammerCollection::load(
189 81
                file($this->source, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES)
190
            );
191 81
        });
192
193 81
        return $this;
194
    }
195
196
    /**
197
     * Allow a host.
198
     *
199
     * @param  string  $host
200
     *
201
     * @return self
202
     */
203 12
    public function allow($host)
204
    {
205 12
        if ( ! empty($host)) {
206 12
            $this->excludes[] = $host;
207
        }
208
209 12
        return $this;
210
    }
211
212
    /**
213
     * Block a host.
214
     *
215
     * @param  string  $host
216
     *
217
     * @return self
218
     */
219 18
    public function block($host)
220
    {
221 18
        if ( ! empty($host)) {
222 18
            $this->includes[] = $host;
223
        }
224
225 18
        return $this;
226
    }
227
228
    /**
229
     * Get all spammers (allowed and blocked ones).
230
     *
231
     * @return \Arcanedev\SpamBlocker\Entities\SpammerCollection
232
     */
233 24
    public function all()
234
    {
235 24
        return $this->spammers()
236 24
            ->includes($this->includes)
237 24
            ->excludes($this->excludes);
238
    }
239
240
    /**
241
     * Check if the given host is allowed.
242
     *
243
     * @param  string  $host
244
     *
245
     * @return bool
246
     */
247 12
    public function isAllowed($host)
248
    {
249 12
        return ! $this->isBlocked($host);
250
    }
251
252
    /**
253
     * Check if the given host is blocked.
254
     *
255
     * @param  string  $host
256
     *
257
     * @return bool
258
     */
259 21
    public function isBlocked($host)
260
    {
261 21
        $host = parse_url($host, PHP_URL_HOST);
262 21
        $host = utf8_encode(trim($host));
263
264 21
        if (empty($host)) return false;
265
266 21
        $fullDomain = $this->getFullDomain($host);
267 21
        $rootDomain = $this->getRootDomain($fullDomain);
268
269 21
        return $this->spammers()
270 21
            ->whereHostIn([$fullDomain, $rootDomain])
271 21
            ->whereBlocked()
272 21
            ->count() > 0;
273
    }
274
275
    /**
276
     * Get a spammer.
277
     *
278
     * @param  string  $host
279
     *
280
     * @return \Arcanedev\SpamBlocker\Entities\Spammer|null
281
     */
282 12
    public function getSpammer($host)
283
    {
284 12
        return $this->all()->getOne($host);
285
    }
286
287
    /**
288
     * Reset the spammers.
289
     *
290
     * @return self
291
     */
292 6
    public function reset()
293
    {
294 6
        return $this->resetCache()
295 6
             ->setIncludes([])
296 6
             ->setExcludes([])
297 6
             ->load();
298
    }
299
300
    /* -----------------------------------------------------------------
301
     |  Other Methods
302
     | -----------------------------------------------------------------
303
     */
304
305
    /**
306
     * Get the full domain.
307
     *
308
     * @param  string  $host
309
     *
310
     * @return string
311
     */
312 21
    protected function getFullDomain($host)
313
    {
314 21
        preg_match('/^(?:[^@\n]+@)?(?:www\.)?([^:\/\n]+)/', $host, $matches);
315
316 21
        return $matches[1];
317
    }
318
319
    /**
320
     * Get the root domain.
321
     *
322
     * @param  string  $domain
323
     *
324
     * @return string
325
     */
326 21
    private function getRootDomain($domain)
327
    {
328 21
        $domainParts = explode('.', $domain);
329 21
        $count       = count($domainParts);
330
331 21
        return $count > 1
332 21
            ? $domainParts[$count - 2].'.'.$domainParts[$count - 1]
333 21
            : $domainParts[0];
334
    }
335
336
    /**
337
     * Reset the cache.
338
     *
339
     * @return self
340
     */
341 6
    protected function resetCache()
342
    {
343 6
        cache()->forget($this->cacheKey);
344
345 6
        return $this;
346
    }
347
348
    /**
349
     * Cache the spammers.
350
     *
351
     * @param  \Closure  $callback
352
     *
353
     * @return \Arcanedev\SpamBlocker\Entities\SpammerCollection
354
     */
355 81
    private function cacheSpammers(Closure $callback)
356
    {
357 81
        return cache()->remember($this->cacheKey, $this->cacheExpires, $callback);
358
    }
359
360
    /**
361
     * Check the source file.
362
     */
363 81
    private function checkSource()
364
    {
365 81
        if ( ! file_exists($this->source)) {
366 6
            throw new Exceptions\SpammerSourceNotFound(
367 6
                "The spammers source file not found in [{$this->source}]."
368
            );
369
        }
370 81
    }
371
}
372