DeCaptchaAbstract::getParams()   F
last analyzed

Complexity

Conditions 23
Paths 243

Size

Total Lines 54

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 552

Importance

Changes 0
Metric Value
dl 0
loc 54
ccs 0
cts 0
cp 0
rs 2.7958
c 0
b 0
f 0
cc 23
nc 243
nop 2
crap 552

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 jumper423\decaptcha\core;
4
5
use Exception;
6
7
/**
8
 * Class DeCaptchaAbstract.
9
 */
10
abstract class DeCaptchaAbstract implements DeCaptchaInterface
11
{
12
    const RESPONSE_TYPE_STRING = 1;
13
    const RESPONSE_TYPE_JSON = 2;
14
15
    const ACTION_FIELDS = 1;
16
    const ACTION_URI = 2;
17
    const ACTION_METHOD = 3;
18
    const ACTION_JSON = 4;
19
20
    const ACTION_METHOD_POST = 1;
21
    const ACTION_METHOD_GET = 2;
22
23
    const DECODE_FORMAT = 1;
24
    const DECODE_ACTION = 2;
25
    const DECODE_SEPARATOR = 3;
26
    const DECODE_PARAMS = 4;
27
    const DECODE_PARAM_SETTING_MARKER = 5;
28
29
    const PARAM_FIELD_TYPE_STRING = 1;
30
    const PARAM_FIELD_TYPE_INTEGER = 2;
31
    const PARAM_FIELD_TYPE_MIX = 3;
32
    const PARAM_FIELD_TYPE_OBJECT = 4;
33
    const PARAM_FIELD_TYPE_BOOLEAN = 5;
34
    const PARAM_FIELD_TYPE_FLOAT = 6;
35
36
    const PARAM_SLUG_DEFAULT = 1;
37
    const PARAM_SLUG_TYPE = 2;
38
    const PARAM_SLUG_REQUIRE = 3;
39
    const PARAM_SLUG_SPEC = 4;
40
    const PARAM_SLUG_VARIABLE = 5;
41
    const PARAM_SLUG_CODING = 6;
42
    const PARAM_SLUG_NOTWIKI = 7;
43
    const PARAM_SLUG_ENUM = 8;
44
    const PARAM_SLUG_WIKI = 9;
45
46
    const PARAM_SLUG_CODING_BASE64 = 1;
47
48
    const PARAM_SPEC_API_KEY = -1;
49
    const PARAM_SPEC_FILE = -2;
50
    const PARAM_SPEC_CAPTCHA = -3;
51
    const PARAM_SPEC_CODE = -4;
52
53
    /**
54
     * Сервис на который будем загружать капчу.
55
     *
56
     * @var string
57
     */
58
    protected $host;
59
    protected $scheme = 'http';
60
    protected $errorLang = DeCaptchaErrors::LANG_EN;
61
    protected $lastRunTime = null;
62
    /** @var DeCaptchaErrors */
63
    protected $errorObject;
64
    protected $causeAnError = false;
65
66
    protected $limit = [];
67
    protected $paramsSpec = [];
68
    protected $params = [];
69
    protected $limitSettings = [];
70
    protected $decodeSettings = [];
71
    protected $actions = [];
72
    protected $paramsNames = [];
73
74
    protected function resetLimits()
75
    {
76
        foreach ($this->limitSettings as $action => $value) {
77
            $this->limit[$action] = $value;
78
        }
79
    }
80
81
    /**
82
     * @param $action
83
     *
84
     * @return bool
85
     */
86
    protected function limitHasNotYetEnded($action)
87
    {
88
        return $this->limit[$action]-- > 0;
89
    }
90
91
    /**
92 3
     * @param $action
93
     * @param $data
94 3
     *
95 1
     * @throws DeCaptchaErrors
96 1
     *
97 3
     * @return array
98
     */
99 3
    protected function decodeResponse($action, $data)
100
    {
101
        if (!array_key_exists($action, $this->decodeSettings[static::DECODE_ACTION])) {
102
            throw new DeCaptchaErrors('нет action');
103
        }
104
        $decodeSetting = $this->decodeSettings[static::DECODE_ACTION][$action];
105
        $decodeFormat = array_key_exists(static::DECODE_FORMAT, $decodeSetting) ?
106
            $decodeSetting[static::DECODE_FORMAT] :
107
            $this->decodeSettings[static::DECODE_FORMAT];
108
        $values = [];
109
        switch ($decodeFormat) {
110
            case static::RESPONSE_TYPE_STRING:
111 View Code Duplication
                foreach (explode($decodeSetting[static::DECODE_SEPARATOR], $data) as $key => $value) {
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated across your project.

Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.

You can also find more detailed suggestions in the “Code” section of your repository.

Loading history...
112
                    foreach ($decodeSetting[static::DECODE_PARAMS] as $param => $paramSetting) {
113
                        if ($key === $paramSetting[static::DECODE_PARAM_SETTING_MARKER]) {
114 3
                            $values[$param] = $value;
115 3
                        }
116 2
                    }
117 2
                }
118 1
                break;
119 1
            case static::RESPONSE_TYPE_JSON:
120 1
                foreach (json_decode($data, true) as $key => $value) {
121 1
                    foreach ($decodeSetting[static::DECODE_PARAMS] as $param => $paramSetting) {
122
                        if (count(explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])) > 1) {
123
                            if ($key === explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])[0]) {
124 1
                                if (array_key_exists(explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])[1], $value)) {
125 1
                                    $values[$param] = $value[explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])[1]];
126
                                }
127 2
                            }
128 1
                        }
129
                        if ($key === $paramSetting[static::DECODE_PARAM_SETTING_MARKER]) {
130 1
                            $values[$param] = $value;
131
                        }
132
                    }
133
                }
134
                break;
135
        }
136 4
137 4
        return $values;
138
    }
139
140
    /**
141
     * @param $errorLang
142
     */
143
    public function setErrorLang($errorLang)
144 2
    {
145 2
        $this->errorLang = $errorLang;
146
    }
147
148
    /**
149
     * Узнаём путь до файла
150
     * Если передана ссылка, то скачиваем и кладём во временную директорию.
151
     *
152 1
     * @param string $fileName
153 1
     *
154
     * @throws Exception
155
     *
156
     * @return string
157
     */
158
    protected function getFilePath($fileName)
159 1
    {
160 1
        if (strpos($fileName, 'http://') !== false || strpos($fileName, 'https://') !== false) {
161
            try {
162
                $current = file_get_contents($fileName);
163
            } catch (\Exception $e) {
164
                throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_FILE_IS_NOT_LOADED, $fileName, $this->errorLang);
165
            }
166
            $path = tempnam(sys_get_temp_dir(), 'captcha');
167
            file_put_contents($path, $current);
168
169 2
            return $path;
170
        }
171 2
        if (file_exists($fileName)) {
172 1
            return $fileName;
173
        }
174 1
175
        throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_FILE_NOT_FOUND, $fileName, $this->errorLang);
176
    }
177
178
    /**
179
     * @param $action
180
     *
181
     * @return string
182
     */
183
    protected function getActionUrl($action)
184
    {
185 1
        return $this->getBaseUrl().$this->actions[$action][static::ACTION_URI];
186 1
    }
187 1
188 1
    /**
189 1
     * @return string
190 1
     */
191 1
    protected function getBaseUrl()
192 1
    {
193
        return "{$this->scheme}://{$this->host}/";
194
    }
195
196
    /**
197
     * @param $params
198
     */
199
    public function setParams($params)
200
    {
201
        if (is_array($params)) {
202
            foreach ($params as $param => $value) {
203
                $this->params[$param] = $value;
204
            }
205
        }
206
    }
207
208
    /**
209
     * @param $param
210
     * @param $value
211
     */
212
    public function setParam($param, $value)
213
    {
214
        $this->params[$param] = $value;
215
    }
216
217
    /**
218
     * @param $param
219
     * @param $spec
220
     * @param $coding
221
     *
222
     * @return \CURLFile|mixed|null|string
223
     */
224
    public function getParamSpec($param, $spec = null, $coding = null)
225
    {
226
        if (is_null($spec)) {
227
            $spec = $param;
228
        }
229
        if (!array_key_exists($param, $this->params) || is_null($this->params[$param])) {
230
            if (!array_key_exists($spec, $this->params) || is_null($this->params[$spec])) {
231
                return null;
232
            }
233
            $param = $spec;
234
        }
235
        switch ($spec) {
236
            case static::PARAM_SPEC_FILE:
237
                switch ($coding) {
238
                    case static::PARAM_SLUG_CODING_BASE64:
239
                        return base64_encode(file_get_contents($this->params[$param]));
240
                }
241
242
                return (version_compare(PHP_VERSION, '5.5.0') >= 0) ? new \CURLFile($this->getFilePath($this->params[$param])) : '@'.$this->getFilePath($this->params[$param]);
243
            case static::PARAM_SPEC_API_KEY:
244
                return is_callable($this->params[$param]) ? $this->params[$param]() : $this->params[$param];
245
            case static::PARAM_SPEC_CAPTCHA:
246
                return (int) $this->params[$param];
247
            case static::PARAM_SPEC_CODE:
248
                return (string) $this->params[$param];
249
        }
250
251
        return null;
252
    }
253
254
    /**
255
     * @param $action
256
     * @param $field
257
     *
258
     * @throws DeCaptchaErrors
259
     *
260
     * @return array
261
     */
262
    protected function getParams($action, $field = null)
263
    {
264
        if (empty($this->actions[$action])) {
265
            return [];
266
        }
267
        $fields = $this->actions[$action][static::ACTION_FIELDS];
268
        if (!is_null($field)) {
269
            $fields = $fields[$field][static::ACTION_FIELDS];
270
        }
271
        $params = [];
272
        foreach ($fields as $field => $settings) {
273
            $value = null;
274
            if (array_key_exists(self::PARAM_SLUG_DEFAULT, $settings)) {
275
                $value = $settings[self::PARAM_SLUG_DEFAULT];
276
            }
277
            if (array_key_exists($field, $this->params) && (!array_key_exists(self::PARAM_SLUG_VARIABLE, $settings) ^ (array_key_exists(self::PARAM_SLUG_VARIABLE, $settings) && $settings[self::PARAM_SLUG_VARIABLE] === false))) {
278
                $value = $this->params[$field];
279
            }
280
            if (array_key_exists(self::PARAM_SLUG_SPEC, $settings)) {
281
                $value = $this->getParamSpec($field, $settings[self::PARAM_SLUG_SPEC], array_key_exists(self::PARAM_SLUG_CODING, $settings) ? $settings[self::PARAM_SLUG_CODING] : null);
282
            }
283
            if (is_null($value)) {
284
                if (array_key_exists(self::PARAM_SLUG_REQUIRE, $settings) && $settings[self::PARAM_SLUG_REQUIRE] === true) {
285
                    throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_PARAM_REQUIRE, array_key_exists($field, $this->paramsNames) ? $this->paramsNames[$field] : $field, $this->errorLang);
286
                }
287
                continue;
288
            }
289
            if (array_key_exists($field, $this->paramsNames)) {
290
                switch ($settings[self::PARAM_SLUG_TYPE]) {
291
                    case self::PARAM_FIELD_TYPE_FLOAT:
292
                        $value = (float) $value;
293
                        break;
294
                    case self::PARAM_FIELD_TYPE_INTEGER:
295
                        $value = (int) $value;
296
                        break;
297
                    case self::PARAM_FIELD_TYPE_STRING:
298
                        $value = (string) $value;
299
                        break;
300
                    case self::PARAM_FIELD_TYPE_BOOLEAN:
301
                        $value = (bool) $value;
302
                        break;
303
                    case self::PARAM_FIELD_TYPE_OBJECT:
304
                        $value = $this->getParams($action, $field);
305
                        break;
306
                }
307
                if (array_key_exists(self::PARAM_SLUG_ENUM, $settings) && !in_array($value, $settings[static::PARAM_SLUG_ENUM])) {
308
                    throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_PARAM_ENUM, (array_key_exists($field, $this->paramsNames) ? $this->paramsNames[$field] : $field).' = '.$value, $this->errorLang);
309
                }
310
                $params[$this->paramsNames[$field]] = $value;
311
            }
312
        }
313
314
        return $params;
315
    }
316
317
    /**
318
     * @param string $action
319
     *
320
     * @return string
321
     */
322
    protected function getResponse($action)
323
    {
324
        return $this->curlResponse(
325
            $this->getActionUrl($action),
326
            $this->getParams($action),
327
            array_key_exists(static::ACTION_METHOD, $this->actions[$action]) && $this->actions[$action][static::ACTION_METHOD] === static::ACTION_METHOD_POST,
328
            array_key_exists(static::ACTION_JSON, $this->actions[$action]) && $this->actions[$action][static::ACTION_JSON] === true
329
        );
330
    }
331
332
    /**
333
     * Задержка выполнения.
334
     *
335
     * @param int           $delay    Количество секунд
336
     * @param \Closure|null $callback
337
     *
338
     * @return mixed
339
     */
340
    protected function executionDelayed($delay = 0, $callback = null)
341
    {
342
        $time = microtime(true);
343
        $timePassed = $time - $this->lastRunTime;
344
        if ($timePassed < $delay) {
345
            usleep(($delay - $timePassed) * 1000000);
346
        }
347
        $this->lastRunTime = microtime(true);
348
349
        return $callback instanceof \Closure ? $callback($this) : $callback;
350
    }
351
352
    /**
353
     * @param string $url
354
     * @param array  $data
355
     * @param bool   $isPost
356
     * @param bool   $isJson
357
     *
358
     * @throws DeCaptchaErrors
359
     *
360
     * @return string
361
     */
362
    protected function curlResponse($url, $data, $isPost = true, $isJson = false)
363
    {
364
        $curl = curl_init();
365
        if ($isJson) {
366
            $data = json_encode($data);
367
        } elseif (!$isPost) {
368
            $uri = [];
369
            foreach ($data as $key => $value) {
370
                $uri[] = "$key=$value";
371
            }
372
            $url .= '?'.implode('&', $uri);
373
        }
374
        curl_setopt($curl, CURLOPT_URL, $url);
375
        if (!$isJson && version_compare(PHP_VERSION, '5.5.0') >= 0 && version_compare(PHP_VERSION, '7.0') < 0 && defined('CURLOPT_SAFE_UPLOAD')) {
376
            curl_setopt($curl, CURLOPT_SAFE_UPLOAD, false);
377
        }
378
        curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
379
        curl_setopt($curl, CURLOPT_ENCODING, 'gzip,deflate');
380
        curl_setopt($curl, CURLOPT_TIMEOUT, 30);
381
        curl_setopt($curl, CURLOPT_CONNECTTIMEOUT, 30);
382
        curl_setopt($curl, CURLOPT_POST, $isPost);
383
        if ($isPost) {
384
            curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
385
        }
386
        if ($isJson) {
387
            curl_setopt($curl, CURLOPT_HTTPHEADER, [
388
                'Content-Type: application/json; charset=utf-8',
389
                'Accept: application/json',
390
                'Content-Length: '.strlen($data),
391
            ]);
392
        }
393
        $result = curl_exec($curl);
394
        if (curl_errno($curl)) {
395
            throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_CURL, curl_error($curl), $this->errorLang);
396
        }
397
        curl_close($curl);
398
399
        return $result;
400
    }
401
402
    abstract public function getCode();
403
404
    abstract public function getError();
405
}
406