Issues (281)

Branch: master

src/ForkCMS/Utility/Akismet.php (1 issue)

1
<?php
2
3
namespace ForkCMS\Utility;
4
5
use GuzzleHttp\Client;
6
use GuzzleHttp\Exception\ClientException;
7
use GuzzleHttp\Exception\ServerException;
8
9
/**
10
 * Akismet class
11
 *
12
 * @author Tijs Verkoyen <[email protected]>
13
 * @author Jacob van Dam <[email protected]>
14
 * @version 2.0.0
15
 * @copyright Copyright (c) Tijs Verkoyen. All rights reserved.
16
 * @license BSD License
17
 */
18
class Akismet
19
{
20
    // internal constant to enable/disable debugging
21
    const DEBUG = false;
22
23
    // url for the api
24
    const API_URL = 'https://rest.akismet.com';
25
26
    // version of the api
27
    const API_VERSION = '1.1';
28
29
    // current version
30
    const VERSION = '2.0.0';
31
32
    /**
33
     * The key for the API
34
     * @var string
35
     */
36
    private string $apiKey;
37
38
    /**
39
     * The timeout
40
     * @var int
41
     */
42
    private int $timeOut = 60;
43
44
    /**
45
     * The user agent
46
     * @var string
47
     */
48
    private string $userAgent;
49
50
    /**
51
     * The url
52
     * @var string
53
     */
54
    private string $url;
55
56
    /**
57
     * Default constructor
58
     * Creates an instance of the Akismet Class.
59
     *
60
     * @param string $apiKey API key being verified for use with the API.
61
     * @param string $url The front page or home URL of the instance making
62
     *                       the request. For a blog or wiki this would be the
63
     *                       front page. Note: Must be a full URI, including
64
     *                       http://.
65
     */
66
    public function __construct(string $apiKey, string $url)
67
    {
68
        $this->setApiKey($apiKey);
69
        $this->setUrl($url);
70
    }
71
72
    /**
73
     * Make the call
74
     * @param string $url URL to call.
75
     * @param array $parameters The parameters to pass.
76
     * @param bool $authenticate Should we authenticate?
77
     * @return string
78
     * @throws \Exception
79
     */
80
    private function doCall(string $url, array $parameters = [], bool $authenticate = true)
81
    {
82
        // add key in front of url
83
        if ($authenticate) {
84
            // get api key
85
            $apiKey = $this->getApiKey();
86
87
            // validate apiKey
88
            if ($apiKey == '') {
89
                throw new \Exception('Invalid API-key');
90
            }
91
        }
92
93
        // add url into the parameters
94
        $parameters['blog'] = $this->getUrl();
95
96
        $client = new Client([
97
            'base_uri' => self::API_URL . '/' . self::API_VERSION . '/',
98
            'timeout' => self::getTimeOut(),
0 ignored issues
show
Bug Best Practice introduced by
The method ForkCMS\Utility\Akismet::getTimeOut() is not static, but was called statically. ( Ignorable by Annotation )

If this is a false-positive, you can also ignore this issue in your code via the ignore-call  annotation

98
            'timeout' => self::/** @scrutinizer ignore-call */ getTimeOut(),
Loading history...
99
        ]);
100
101
        try {
102
            $response = $client->post($url, [
103
                'form_params' => $parameters,
104
                'headers' => [
105
                    'User-Agent' => $this->getUserAgent(),
106
                ],
107
            ]);
108
        } catch (ClientException|ServerException $e) {
109
            throw new \Exception($e->getMessage(), $e->getCode());
110
        }
111
112
        return $response->getBody()->getContents();
113
    }
114
115
    /**
116
     * Get the API-key that will be used
117
     *
118
     * @return string
119
     */
120
    private function getApiKey(): string
121
    {
122
        return $this->apiKey;
123
    }
124
125
    /**
126
     * Get the timeout that will be used
127
     *
128
     * @return int
129
     */
130
    public function getTimeOut(): int
131
    {
132
        return $this->timeOut;
133
    }
134
135
    /**
136
     * Get the url of the instance making the request
137
     *
138
     * @return string
139
     */
140
    public function getUrl(): string
141
    {
142
        return $this->url;
143
    }
144
145
    /**
146
     * Get the useragent that will be used.
147
     * Our version will be prepended to yours. It will look like:
148
     * "PHP Akismet/<version> <your-user-agent>"
149
     *
150
     * @return string
151
     */
152
    public function getUserAgent(): string
153
    {
154
        return 'PHP Akismet/' . self::VERSION . ' ' . $this->userAgent;
155
    }
156
157
    /**
158
     * Set API key that has to be used
159
     *
160
     * @param string $apiKey API key to use.
161
     */
162
    private function setApiKey(string $apiKey)
163
    {
164
        $this->apiKey = $apiKey;
165
    }
166
167
    /**
168
     * Set the timeout
169
     * After this time the request will stop. You should handle any errors
170
     * triggered by this.
171
     *
172
     * @param int $seconds The timeout in seconds.
173
     */
174
    public function setTimeOut(int $seconds)
175
    {
176
        $this->timeOut = $seconds;
177
    }
178
179
    /**
180
     * Set the url of the instance making the request
181
     * @param string $url The URL making the request.
182
     */
183
    private function setUrl(string $url)
184
    {
185
        $this->url = $url;
186
    }
187
188
    /**
189
     * Set the user-agent for you application
190
     * It will be appended to ours, the result will look like:
191
     * "PHP Akismet/<version> <your-user-agent>"
192
     *
193
     * @param string $userAgent The user-agent, it should look like:
194
     *                          <app-name>/<app-version>.
195
     */
196
    public function setUserAgent(string $userAgent)
197
    {
198
        $this->userAgent = $userAgent;
199
    }
200
201
    // api methods
202
203
    /**
204
     * Verifies the key
205
     * @return bool if the key is valid it will return true, otherwise false
206
     *              will be returned.
207
     * @throws \Exception
208
     */
209
    public function verifyKey(): bool
210
    {
211
        // possible answers
212
        $aPossibleResponses = ['valid', 'invalid'];
213
214
        // build parameters
215
        $aParameters['key'] = $this->getApiKey();
216
217
        // make the call
218
        $response = $this->doCall('verify-key', $aParameters, false);
219
220
        // validate response
221
        if (!in_array($response, $aPossibleResponses)) {
222
            throw new \Exception($response, 400);
223
        }
224
225
        // valid key
226
        return $response == 'valid';
227
    }
228
229
    /**
230
     * Check if the comment is spam or not
231
     * This is basically the core of everything. This call takes a number of
232
     * arguments and characteristics about the submitted content and then
233
     * returns a thumbs up or thumbs down.
234
     * Almost everything is optional, but performance can drop dramatically if
235
     * you exclude certain elements.
236
     * REMARK: If you are having trouble triggering you can send
237
     * "viagra-test-123" as the author and it will trigger a true response,
238
     * always.
239
     *
240
     * @param string $content The content that was submitted.
241
     * @param string|null $author The name.
242
     * @param string|null $email The email address.
243
     * @param string|null $url The URL.
244
     * @param string|null $permalink The permanent location of the entry
245
     *                                    the comment was submitted to.
246
     * @param string|null $type The type, can be blank, comment,
247
     *                                    trackback, pingback, or a made up
248
     *                                    value like "registration".
249
     * @return bool If the comment is spam true will be
250
     *                                    returned, otherwise false.
251
     * @throws \Exception
252
     */
253
    public function isSpam(
254
        string $content,
255
        string $author = null,
256
        string $email = null,
257
        string $url = null,
258
        string $permalink = null,
259
        string $type = null
260
    ): bool {
261
        // possible answers
262
        $possibleResponses = ['true', 'false'];
263
264
        // get stuff from the $_SERVER-array
265
        if (isset($_SERVER['HTTP_X_FORWARDED_FOR'])) {
266
            $ip = $_SERVER['HTTP_X_FORWARDED_FOR'];
267
        } elseif (isset($_SERVER['REMOTE_ADDR'])) {
268
            $ip = $_SERVER['REMOTE_ADDR'];
269
        } else {
270
            $ip = '';
271
        }
272
273
        if (isset($_SERVER['HTTP_USER_AGENT'])) {
274
            $userAgent = (string)$_SERVER['HTTP_USER_AGENT'];
275
        } else {
276
            $userAgent = '';
277
        }
278
279
        if (isset($_SERVER['HTTP_REFERER'])) {
280
            $referrer = (string)$_SERVER['HTTP_REFERER'];
281
        } else {
282
            $referrer = '';
283
        }
284
285
        // build parameters
286
        $parameters = [];
287
        $parameters['user_ip'] = $ip;
288
        $parameters['user_agent'] = $userAgent;
289
        if ($referrer) {
290
            $parameters['referrer'] = $referrer;
291
        }
292
        if ($permalink) {
293
            $parameters['permalink'] = $permalink;
294
        }
295
        if ($type) {
296
            $parameters['comment_type'] = $type;
297
        }
298
        if ($author) {
299
            $parameters['comment_author'] = $author;
300
        }
301
        if ($email) {
302
            $parameters['comment_author_email'] = $email;
303
        }
304
        if ($url) {
305
            $parameters['comment_author_url'] = $url;
306
        }
307
        $parameters['comment_content'] = $content;
308
309
        // add all stuff from $_SERVER
310
        foreach ($_SERVER as $key => $value) {
311
            // keys to ignore
312
            $keysToIgnore = [
313
                'HTTP_COOKIE',
314
                'HTTP_X_FORWARDED_FOR',
315
                'HTTP_X_FORWARDED_HOST',
316
                'HTTP_MAX_FORWARDS',
317
                'HTTP_X_FORWARDED_SERVER',
318
                'REDIRECT_STATUS',
319
                'SERVER_PORT',
320
                'PATH',
321
                'DOCUMENT_ROOT',
322
                'SERVER_ADMIN',
323
                'QUERY_STRING',
324
                'PHP_SELF',
325
                'argv',
326
                'argc',
327
                'SCRIPT_FILENAME',
328
                'SCRIPT_NAME',
329
            ];
330
331
            // add to parameters if not in ignore list
332
            if (!in_array($key, $keysToIgnore)) {
333
                $parameters[$key] = $value;
334
            }
335
        }
336
337
        // make the call
338
        $response = $this->doCall('comment-check', $parameters);
339
340
        // validate response
341
        if (!in_array($response, $possibleResponses)) {
342
            throw new \Exception($response, 400);
343
        }
344
345
        return $response == 'true';
346
    }
347
348
    /**
349
     * Submit ham to Akismet
350
     * This call is intended for the marking of false positives, things that
351
     * were incorrectly marked as spam.
352
     * @param string $userIp The address of the comment submitter.
353
     * @param string $userAgent The agent information.
354
     * @param string $content The content that was submitted.
355
     * @param string|null $author The name of the author.
356
     * @param string|null $email The email address.
357
     * @param string|null $url The URL.
358
     * @param string|null $permalink The permanent location of the entry
359
     *                                    the comment was submitted to.
360
     * @param string|null $type The type, can be blank, comment,
361
     *                                    trackback, pingback, or a made up
362
     *                                    value like "registration".
363
     * @param string|null $referrer The content of the HTTP_REFERER
364
     *                                    header should be sent here.
365
     * @param array $others Extra data (the variables from
366
     *                                    $_SERVER).
367
     * @return bool If everything went fine true will be
368
     *                                    returned, otherwise an exception
369
     *                                    will be triggered.
370
     * @throws \Exception
371
     */
372
    public function submitHam(
373
        string $userIp,
374
        string $userAgent,
375
        string $content,
376
        string $author = null,
377
        string $email = null,
378
        string $url = null,
379
        string $permalink = null,
380
        string $type = null,
381
        string $referrer = null,
382
        array  $others = []
383
    ): bool {
384
        // possible answers
385
        $possibleResponses = ['Thanks for making the web a better place.'];
386
387
        // build parameters
388
        $parameters = [];
389
        $parameters['user_ip'] = $userIp;
390
        $parameters['user_agent'] = $userAgent;
391
392
        if ($referrer) {
393
            $parameters['referrer'] = $referrer;
394
        }
395
396
        if ($permalink) {
397
            $parameters['permalink'] = $permalink;
398
        }
399
400
        if ($type) {
401
            $parameters['comment_type'] = $type;
402
        }
403
        if ($author) {
404
            $parameters['comment_author'] = $author;
405
        }
406
        if ($email) {
407
            $parameters['comment_author_email'] = $email;
408
        }
409
        if ($url) {
410
            $parameters['comment_author_url'] = $url;
411
        }
412
        $parameters['comment_content'] = $content;
413
414
        // add other parameters
415
        foreach ($others as $key => $value) {
416
            $parameters[$key] = $value;
417
        }
418
419
        // make the call
420
        $response = $this->doCall('submit-ham', $parameters);
421
422
        // validate response
423
        if (in_array($response, $possibleResponses)) {
424
            return true;
425
        }
426
427
        // fallback
428
        throw new \Exception($response);
429
    }
430
431
    /**
432
     * Submit spam to Akismet
433
     * This call is for submitting comments that weren't marked as spam but
434
     * should have been.
435
     * @param string $userIp The address of the comment submitter.
436
     * @param string $userAgent The agent information.
437
     * @param string $content The content that was submitted.
438
     * @param string|null $author The name of the author.
439
     * @param string|null $email The email address.
440
     * @param string|null $url The URL.
441
     * @param string|null $permalink The permanent location of the entry
442
     *                                    the comment was submitted to.
443
     * @param string|null $type The type, can be blank, comment,
444
     *                                    trackback, pingback, or a made up
445
     *                                    value like "registration".
446
     * @param string|null $referrer The content of the HTTP_REFERER
447
     *                                    header should be sent here.
448
     * @param array $others Extra data (the variables from
449
     *                                    $_SERVER).
450
     * @return bool If everything went fine true will be
451
     *                                    returned, otherwise an exception
452
     *                                    will be triggered.
453
     * @throws \Exception
454
     */
455
    public function submitSpam(
456
        string $userIp,
457
        string $userAgent,
458
        string $content,
459
        string $author = null,
460
        string $email = null,
461
        string $url = null,
462
        string $permalink = null,
463
        string $type = null,
464
        string $referrer = null,
465
        array  $others = []
466
    ): bool {
467
        // possible answers
468
        $possibleResponses = ['Thanks for making the web a better place.'];
469
470
        // build parameters
471
        $parameters['user_ip'] = $userIp;
472
        $parameters['user_agent'] = $userAgent;
473
        if ($referrer) {
474
            $parameters['referrer'] = $referrer;
475
        }
476
        if ($permalink) {
477
            $parameters['permalink'] = $permalink;
478
        }
479
        if ($type) {
480
            $parameters['comment_type'] = $type;
481
        }
482
        if ($author) {
483
            $parameters['comment_author'] = $author;
484
        }
485
        if ($email) {
486
            $parameters['comment_author_email'] = $email;
487
        }
488
        if ($url) {
489
            $parameters['comment_author_url'] = $url;
490
        }
491
        $parameters['comment_content'] = $content;
492
493
        // add other parameters
494
        foreach ($others as $key => $value) {
495
            $parameters[$key] = $value;
496
        }
497
498
        // make the call
499
        $response = $this->doCall('submit-spam', $parameters);
500
501
        // validate response
502
        if (in_array($response, $possibleResponses)) {
503
            return true;
504
        }
505
506
        // fallback
507
        throw new \Exception($response);
508
    }
509
}
510