Passed
Pull Request — master (#135)
by
unknown
03:02
created

RecaptchaAdapter::getErrorCodes()   B

Complexity

Conditions 10
Paths 2

Size

Total Lines 66
Code Lines 44

Duplication

Lines 0
Ratio 0 %

Importance

Changes 1
Bugs 0 Features 0
Metric Value
cc 10
eloc 44
c 1
b 0
f 0
nc 2
nop 0
dl 0
loc 66
rs 7.6666

How to fix   Long Method    Complexity   

Long Method

Small methods make your code easier to understand, in particular if combined with a good name. Besides, if your method is small, finding a good name is usually much easier.

For example, if you find yourself adding comments to a method's body, this is usually a good sign to extract the commented part to a new method, and use the comment as a starting point when coming up with a good name for this new method.

Commonly applied refactorings include:

1
<?php
2
3
namespace Quantum\Libraries\Captcha\Adapters;
4
5
use Quantum\Libraries\Captcha\CaptchaInterface;
6
use Quantum\Libraries\Curl\HttpClient;
7
8
class RecaptchaAdapter implements CaptchaInterface
9
{
10
    /**
11
     * ReCAPTCHA URL verifying
12
     *
13
     * @var string
14
     */
15
    const VERIFY_URL = 'https://www.google.com/recaptcha/api/siteverify';
16
17
    const CLIENT_API = 'https://www.google.com/recaptcha/api.js';
18
19
    /**
20
     * Public key
21
     *
22
     * @var string
23
     */
24
    private $sitekey;
25
26
    /**
27
     * Private key
28
     *
29
     * @var string
30
     */
31
    private $secretkey;
32
33
    /**
34
     * Remote IP address
35
     *
36
     * @var string
37
     */
38
    protected $remoteIp = null;
39
40
    /**
41
     * Supported themes
42
     *
43
     * @var array
44
     * @see https://developers.google.com/recaptcha/docs/display#config
45
     */
46
    protected static $themes = array('light', 'dark');
47
48
    /**
49
     * Captcha theme. Default : light
50
     *
51
     * @var string
52
     * @see https://developers.google.com/recaptcha/docs/display#config
53
     */
54
    protected $theme = null;
55
56
    /**
57
     * Supported types
58
     *
59
     * @var array
60
     * @see https://developers.google.com/recaptcha/docs/display#config
61
     */
62
    protected static $types = array('image', 'audio');
63
64
    /**
65
     * Captcha type. Default : image
66
     *
67
     * @var string
68
     * @see https://developers.google.com/recaptcha/docs/display#config
69
     */
70
    protected $type = null;
71
72
    /**
73
     * Captcha language. Default : auto-detect
74
     *
75
     * @var string
76
     * @see https://developers.google.com/recaptcha/docs/language
77
     */
78
    protected $language = null;
79
80
    /**
81
     * CURL timeout (in seconds) to verify response
82
     *
83
     * @var int
84
     */
85
    private $verifyTimeout = 1;
86
87
    /**
88
     * Captcha size. Default : normal
89
     *
90
     * @var string
91
     * @see https://developers.google.com/recaptcha/docs/display#render_param
92
     */
93
    protected $size = null;
94
95
    private static $instance = null;
96
97
    /**
98
     * List of errors
99
     *
100
     * @var array
101
     */
102
    protected $errorCodes = array();
103
104
105
    /**
106
     * RecaptchaAdapter
107
     *
108
     * @param array $params
109
     * @return void
110
     */
111
    private function __construct(array $params)
112
    {
113
        $this->http = new HttpClient();
0 ignored issues
show
Bug Best Practice introduced by
The property http does not exist. Although not strictly required by PHP, it is generally a best practice to declare properties explicitly.
Loading history...
114
115
        $this->secretkey = $params['secret_key'];
116
        $this->sitekey = $params['site_key'];
117
        $this->type = $params['type'];
118
    }
119
120
    /**
121
     * Get Instance
122
     * @param array $params
123
     * @return RecaptchaAdapter
124
     */
125
    public static function getInstance(array $params): RecaptchaAdapter
126
    {
127
        if (self::$instance === null) {
128
            self::$instance = new self($params);
129
        }
130
131
        return self::$instance;
132
    }
133
134
    /**
135
     * Set theme
136
     *
137
     * @param string $theme (see https://developers.google.com/recaptcha/docs/display#config)
138
     * @return object
139
     */
140
    public function setTheme($theme = 'light')
141
    {
142
        if (in_array($theme, self::$themes))
143
            $this->theme = $theme;
144
        else
145
            throw new \Exception('Theme "' . $theme . '"" is not supported. Available themes : ' . join(', ', self::$themes));
146
147
        return $this;
148
    }
149
150
    /**
151
     * Set type
152
     *
153
     * @param string $type (see https://developers.google.com/recaptcha/docs/display#config)
154
     * @return object
155
     */
156
    public function setType($type = 'image')
157
    {
158
        if (in_array($type, self::$types))
159
            $this->type = $type;
160
161
        return $this;
162
    }
163
164
    /**
165
     * Set language
166
     *
167
     * @param string $language (see https://developers.google.com/recaptcha/docs/language)
168
     * @return object
169
     */
170
    public function setLanguage($language)
171
    {
172
        $this->language = $language;
173
174
        return $this;
175
    }
176
177
    /**
178
     * Set timeout
179
     *
180
     * @param int $timeout
181
     * @return object
182
     */
183
    public function setVerifyTimeout($timeout)
184
    {
185
        $this->verifyTimeout = $timeout;
186
187
        return $this;
188
    }
189
190
    /**
191
     * Set size
192
     *
193
     * @param string $size (see https://developers.google.com/recaptcha/docs/display#render_param)
194
     * @return object
195
     */
196
    public function setSize($size)
197
    {
198
        $this->size = $size;
199
200
        return $this;
201
    }
202
203
    /**
204
     * Generate the JS code of the captcha
205
     *
206
     * @return string
207
     */
208
    public function renderJs($lang = null, $callback = false, $onLoadClass = 'onloadCallBack')
209
    {
210
        $data = array();
211
        if (!is_null($this->language))
0 ignored issues
show
introduced by
The condition is_null($this->language) is always false.
Loading history...
212
            $data = array('hl' => $this->language);
213
214
        return '<script src="https://www.google.com/recaptcha/api.js?' . http_build_query($data) . '"></script>';
215
    }
216
217
    /**
218
     * Get hCaptcha js link.
219
     *
220
     * @param string $lang
221
     * @param boolean $callback
222
     * @param string $onLoadClass
223
     *
224
     * @return string
225
     */
226
    public function getJsLink($lang = null, $callback = false, $onLoadClass = 'onloadCallBack')
227
    {
228
        $client_api = static::CLIENT_API;
229
        $params = [];
230
231
        $callback ? $this->setCallBackParams($params, $onLoadClass) : false;
0 ignored issues
show
Bug introduced by
The method setCallBackParams() does not exist on Quantum\Libraries\Captch...apters\RecaptchaAdapter. ( Ignorable by Annotation )

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

231
        $callback ? $this->/** @scrutinizer ignore-call */ setCallBackParams($params, $onLoadClass) : false;

This check looks for calls to methods that do not seem to exist on a given type. It looks for the method on the type itself as well as in inherited classes or implemented interfaces.

This is most likely a typographical error or the method has been renamed.

Loading history...
232
        $lang ? $params['hl'] = $lang : null;
233
234
        return $client_api . '?' . http_build_query($params);
235
    }
236
237
    /**
238
     * Generate the HTML code block for the captcha
239
     *
240
     * @return string
241
     */
242
    public function display($formIdentifier = '', $attributes = [])
243
    {
244
        if (!empty($this->sitekey)) {
245
            if (strtolower($this->type) == 'visible'){
246
                $data = 'data-sitekey="' . $this->sitekey . '"';
247
248
                if (!is_null($this->theme))
0 ignored issues
show
introduced by
The condition is_null($this->theme) is always false.
Loading history...
249
                    $data .= ' data-theme="' . $this->theme . '"';
250
251
                if (!is_null($this->type))
0 ignored issues
show
introduced by
The condition is_null($this->type) is always false.
Loading history...
252
                    $data .= ' data-type="' . $this->type . '"';
253
254
                if (!is_null($this->size))
0 ignored issues
show
introduced by
The condition is_null($this->size) is always false.
Loading history...
255
                    $data .= ' data-size="' . $this->size . '"';
256
257
                $captchaEleme = '<div class="col s1 offset-s2 g-recaptcha" ' . $data . '></div>';
258
            } elseif (strtolower($this->type) == 'invisible') {
259
                $captchaEleme = '';
260
                if (!isset($attributes['data-callback'])) {
261
                    $captchaEleme = '<script>
262
                     document.addEventListener("DOMContentLoaded", function() {
263
                        let button = document.getElementsByTagName("button");
264
                    
265
                        button[0].setAttribute("data-sitekey", "' . $this->sitekey . '");
266
                        button[0].setAttribute("data-callback", "onSubmit");
267
                        button[0].setAttribute("data-action", "submit");
268
                        button[0].classList.add("g-recaptcha");
269
                     })
270
                    
271
                    function onSubmit (token){
272
                        document.getElementById("'. $formIdentifier .'").submit();
273
                    }
274
                </script>';
275
                }
276
            }
277
            return $captchaEleme;
0 ignored issues
show
Comprehensibility Best Practice introduced by
The variable $captchaEleme does not seem to be defined for all execution paths leading up to this point.
Loading history...
278
        }
279
    }
280
281
    /**
282
     * Checks the code given by the captcha
283
     *
284
     * @param string $response Response code after submitting form (usually $_POST['g-recaptcha-response'])
285
     * @return bool
286
     */
287
    public function verifyResponse($response, $clientIp = null)
288
    {
289
        if (is_null($this->secretkey))
0 ignored issues
show
introduced by
The condition is_null($this->secretkey) is always false.
Loading history...
290
            throw new \Exception('You must set your secret key');
291
292
        if (empty($response)) {
293
294
            $this->errorCodes = array('internal-empty-response');
295
296
            return false;
297
        }
298
299
        $query = array(
300
            'secret' => $this->secretkey,
301
            'response' => $response,
302
            'remoteip' => $this->remoteIp,
303
        );
304
305
        $url = self::VERIFY_URL . '?' . http_build_query($query);
306
307
        $this->http->createRequest($url)->setMethod('GET')->start();
308
        $response = (array)$this->http->getResponseBody();
309
310
        if (empty($response) || is_null($response) || !$response) {
0 ignored issues
show
Bug Best Practice introduced by
The expression $response of type array is implicitly converted to a boolean; are you sure this is intended? If so, consider using empty($expr) instead to make it clear that you intend to check for an array without elements.

This check marks implicit conversions of arrays to boolean values in a comparison. While in PHP an empty array is considered to be equal (but not identical) to false, this is not always apparent.

Consider making the comparison explicit by using empty(..) or ! empty(...) instead.

Loading history...
311
            return false;
312
        }
313
314
        if (isset($response['error-codes'])) {
315
            $this->errorCodes = $response['error-codes'];
316
        }
317
318
        return $response['success'];
319
    }
320
321
    /**
322
     * Returns the errors encountered
323
     *
324
     * @return array Errors code and name
325
     */
326
    public function getErrorCodes()
327
    {
328
        $errors = array();
329
330
        if (count($this->errorCodes) > 0) {
331
            foreach ($this->errorCodes as $error) {
332
                switch ($error) {
333
                    case 'timeout-or-duplicate':
334
                        $errors[] = array(
335
                            'code' => $error,
336
                            'name' => 'Timeout or duplicate.',
337
                        );
338
                        break;
339
340
                    case 'missing-input-secret':
341
                        $errors[] = array(
342
                            'code' => $error,
343
                            'name' => 'The secret parameter is missing.',
344
                        );
345
                        break;
346
347
                    case 'invalid-input-secret':
348
                        $errors[] = array(
349
                            'code' => $error,
350
                            'name' => 'The secret parameter is invalid or malformed.',
351
                        );
352
                        break;
353
354
                    case 'missing-input-response':
355
                        $errors[] = array(
356
                            'code' => $error,
357
                            'name' => 'The response parameter is missing.',
358
                        );
359
                        break;
360
361
                    case 'invalid-input-response':
362
                        $errors[] = array(
363
                            'code' => $error,
364
                            'name' => 'The response parameter is invalid or malformed.',
365
                        );
366
                        break;
367
368
                    case 'bad-request':
369
                        $errors[] = array(
370
                            'code' => $error,
371
                            'name' => 'The request is invalid or malformed.',
372
                        );
373
                        break;
374
375
                    case 'internal-empty-response':
376
                        $errors[] = array(
377
                            'code' => $error,
378
                            'name' => 'The recaptcha response is required.',
379
                        );
380
                        break;
381
382
                    default:
383
                        $errors[] = array(
384
                            'code' => $error,
385
                            'name' => $error,
386
                        );
387
                }
388
            }
389
        }
390
391
        return $errors;
392
    }
393
    
394
}