Completed
Push — master ( 951257...e75ae0 )
by Владислав
02:19
created

DeCaptchaAbstract::getParams()   C

Complexity

Conditions 21
Paths 147

Size

Total Lines 51
Code Lines 38

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 462

Importance

Changes 0
Metric Value
dl 0
loc 51
ccs 0
cts 0
cp 0
rs 5.1692
c 0
b 0
f 0
cc 21
eloc 38
nc 147
nop 2
crap 462

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
35
    const PARAM_SLUG_DEFAULT = 1;
36
    const PARAM_SLUG_TYPE = 2;
37
    const PARAM_SLUG_REQUIRE = 3;
38
    const PARAM_SLUG_SPEC = 4;
39
    const PARAM_SLUG_VARIABLE = 5;
40
    const PARAM_SLUG_CODING = 6;
41
42
    const PARAM_SLUG_CODING_BASE64 = 1;
43
44
    const PARAM_SPEC_API_KEY = -1;
45
    const PARAM_SPEC_FILE = -2;
46
    const PARAM_SPEC_CAPTCHA = -3;
47
    const PARAM_SPEC_CODE = -4;
48
49
    /**
50
     * Сервис на который будем загружать капчу.
51
     *
52
     * @var string
53
     */
54
    protected $host;
55
    protected $scheme = 'http';
56
    protected $errorLang = DeCaptchaErrors::LANG_EN;
57
    protected $lastRunTime = null;
58
    /** @var DeCaptchaErrors */
59
    protected $errorObject;
60
    protected $causeAnError = false;
61
62
    protected $limit = [];
63
    protected $paramsSpec = [];
64
    protected $params = [];
65
    protected $limitSettings = [];
66
    protected $decodeSettings = [];
67
    protected $actions = [];
68
    protected $paramsNames = [];
69
70
    protected function resetLimits()
71
    {
72
        foreach ($this->limitSettings as $action => $value) {
73
            $this->limit[$action] = $value;
74
        }
75
    }
76
77
    /**
78
     * @param $action
79
     *
80
     * @return bool
81
     */
82
    protected function limitHasNotYetEnded($action)
83
    {
84
        return $this->limit[$action]-- > 0;
85
    }
86
87
    /**
88
     * @param $action
89
     * @param $data
90
     *
91
     * @throws DeCaptchaErrors
92 3
     *
93
     * @return array
94 3
     */
95 1
    protected function decodeResponse($action, $data)
96 1
    {
97 3
        if (!array_key_exists($action, $this->decodeSettings[static::DECODE_ACTION])) {
98
            throw new DeCaptchaErrors('нет action');
99 3
        }
100
        $decodeSetting = $this->decodeSettings[static::DECODE_ACTION][$action];
101
        $decodeFormat = array_key_exists(static::DECODE_FORMAT, $decodeSetting) ?
102
            $decodeSetting[static::DECODE_FORMAT] :
103
            $this->decodeSettings[static::DECODE_FORMAT];
104
        $values = [];
105
        switch ($decodeFormat) {
106
            case static::RESPONSE_TYPE_STRING:
107
                foreach (explode($decodeSetting[static::DECODE_SEPARATOR], $data) as $key => $value) {
108
                    foreach ($decodeSetting[static::DECODE_PARAMS] as $param => $paramSetting) {
109
                        if ($key === $paramSetting[static::DECODE_PARAM_SETTING_MARKER]) {
110
                            $values[$param] = $value;
111
                        }
112
                    }
113
                }
114 3
                break;
115 3
            case static::RESPONSE_TYPE_JSON:
116 2
                foreach (json_decode($data, true) as $key => $value) {
117 2
                    foreach ($decodeSetting[static::DECODE_PARAMS] as $param => $paramSetting) {
118 1
                        if (count(explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])) > 1) {
119 1
                            if ($key === explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])[0]) {
120 1
                                if (array_key_exists(explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])[1], $value)) {
121 1
                                    $values[$param] = $value[explode('.', $paramSetting[static::DECODE_PARAM_SETTING_MARKER])[1]];
122
                                }
123
                            }
124 1
                        }
125 1
                        if ($key === $paramSetting[static::DECODE_PARAM_SETTING_MARKER]) {
126
                            $values[$param] = $value;
127 2
                        }
128 1
                    }
129
                }
130 1
                break;
131
        }
132
133
        return $values;
134
    }
135
136 4
    /**
137 4
     * @param $errorLang
138
     */
139
    public function setErrorLang($errorLang)
140
    {
141
        $this->errorLang = $errorLang;
142
    }
143
144 2
    /**
145 2
     * Узнаём путь до файла
146
     * Если передана ссылка, то скачиваем и кладём во временную директорию.
147
     *
148
     * @param string $fileName
149
     *
150
     * @throws Exception
151
     *
152 1
     * @return string
153 1
     */
154
    protected function getFilePath($fileName)
155
    {
156
        if (strpos($fileName, 'http://') !== false || strpos($fileName, 'https://') !== false) {
157
            try {
158
                $current = file_get_contents($fileName);
159 1
            } catch (\Exception $e) {
160 1
                throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_FILE_IS_NOT_LOADED, $fileName, $this->errorLang);
161
            }
162
            $path = tempnam(sys_get_temp_dir(), 'captcha');
163
            file_put_contents($path, $current);
164
165
            return $path;
166
        }
167
        if (file_exists($fileName)) {
168
            return $fileName;
169 2
        }
170
        throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_FILE_NOT_FOUND, $fileName, $this->errorLang);
171 2
    }
172 1
173
    /**
174 1
     * @param $action
175
     *
176
     * @return string
177
     */
178
    protected function getActionUrl($action)
179
    {
180
        return $this->getBaseUrl().$this->actions[$action][static::ACTION_URI];
181
    }
182
183
    /**
184
     * @return string
185 1
     */
186 1
    protected function getBaseUrl()
187 1
    {
188 1
        return "{$this->scheme}://{$this->host}/";
189 1
    }
190 1
191 1
    /**
192 1
     * @param $params
193
     */
194
    public function setParams($params)
195
    {
196
        if (is_array($params)) {
197
            foreach ($params as $param => $value) {
198
                $this->params[$param] = $value;
199
            }
200
        }
201
    }
202
203
    /**
204
     * @param $param
205
     * @param $value
206
     */
207
    public function setParam($param, $value)
208
    {
209
        $this->params[$param] = $value;
210
    }
211
212
    /**
213
     * @param $param
214
     * @param $coding
215
     *
216
     * @return \CURLFile|mixed|null|string
217
     */
218
    public function getParamSpec($param, $coding = null)
219
    {
220
        if (!array_key_exists($param, $this->params) || is_null($this->params[$param])) {
221
            return null;
222
        }
223
        switch ($param) {
224
            case static::PARAM_SPEC_FILE:
225
                switch ($coding) {
226
                    case static::PARAM_SLUG_CODING_BASE64:
227
                        return base64_encode(file_get_contents($this->params[$param]));
228
                }
229
230
                return (version_compare(PHP_VERSION, '5.5.0') >= 0) ? new \CURLFile($this->getFilePath($this->params[$param])) : '@'.$this->getFilePath($this->params[$param]);
231
            case static::PARAM_SPEC_API_KEY:
232
                return is_callable($this->params[$param]) ? $this->params[$param]() : $this->params[$param];
233
            case static::PARAM_SPEC_CAPTCHA:
234
                return (int) $this->params[$param];
235
            case static::PARAM_SPEC_CODE:
236
                return (string) $this->params[$param];
237
        }
238
239
        return null;
240
    }
241
242
    /**
243
     * @param $action
244
     * @param $field
245
     *
246
     * @throws DeCaptchaErrors
247
     *
248
     * @return array
249
     */
250
    protected function getParams($action, $field = null)
251
    {
252
        if (empty($this->actions[$action])) {
253
            return [];
254
        }
255
        if (!is_null($field)) {
256
            $fields = $this->actions[$action][static::ACTION_FIELDS][$field][static::ACTION_FIELDS];
257
        } else {
258
            $fields = $this->actions[$action][static::ACTION_FIELDS];
259
        }
260
        $params = [];
261
        foreach ($fields as $field => $settings) {
262
            $value = null;
263
            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))) {
264
                $value = $this->params[$field];
265
            }
266
            if (array_key_exists(self::PARAM_SLUG_DEFAULT, $settings)) {
267
                $value = $settings[self::PARAM_SLUG_DEFAULT];
268
            }
269
            if (array_key_exists(self::PARAM_SLUG_SPEC, $settings) && array_key_exists($settings[self::PARAM_SLUG_SPEC], $this->params)) {
270
                $value = $this->getParamSpec($settings[self::PARAM_SLUG_SPEC], array_key_exists(self::PARAM_SLUG_CODING, $settings) ? $settings[self::PARAM_SLUG_CODING] : null);
271
            }
272
            if (is_null($value)) {
273
                if (array_key_exists(self::PARAM_SLUG_REQUIRE, $settings) && $settings[self::PARAM_SLUG_REQUIRE] === true) {
274
                    throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_PARAM_REQUIRE, array_key_exists($field, $this->paramsNames) ? $this->paramsNames[$field] : $field, $this->errorLang);
275
                }
276
                continue;
277
            }
278
            if (array_key_exists($field, $this->paramsNames)) {
279
                switch ($settings[self::PARAM_SLUG_TYPE]) {
280
                    case self::PARAM_FIELD_TYPE_INTEGER:
281
                        $params[$this->paramsNames[$field]] = (int) $value;
282
                        break;
283
                    case self::PARAM_FIELD_TYPE_STRING:
284
                        $params[$this->paramsNames[$field]] = (string) $value;
285
                        break;
286
                    case self::PARAM_FIELD_TYPE_BOOLEAN:
287
                        $params[$this->paramsNames[$field]] = (bool)$value;
288
                        break;
289
                    case self::PARAM_FIELD_TYPE_MIX:
290
                        $params[$this->paramsNames[$field]] = $value;
291
                        break;
292
                    case self::PARAM_FIELD_TYPE_OBJECT:
293
                        $params[$this->paramsNames[$field]] = $this->getParams($action, $field);
294
                        break;
295
                }
296
            }
297
        }
298
299
        return $params;
300
    }
301
302
    /**
303
     * @param string $action
304
     *
305
     * @return string
306
     */
307
    protected function getResponse($action)
308
    {
309
        return $this->getCurlResponse(
310
            $this->getActionUrl($action),
311
            $this->getParams($action),
312
            array_key_exists(static::ACTION_METHOD, $this->actions[$action]) && $this->actions[$action][static::ACTION_METHOD] === static::ACTION_METHOD_POST,
313
            array_key_exists(static::ACTION_JSON, $this->actions[$action]) && $this->actions[$action][static::ACTION_JSON] === true
314
        );
315
    }
316
317
    /**
318
     * Задержка выполнения.
319
     *
320
     * @param int           $delay    Количество секунд
321
     * @param \Closure|null $callback
322
     *
323
     * @return mixed
324
     */
325
    protected function executionDelayed($delay = 0, $callback = null)
326
    {
327
        $time = microtime(true);
328
        $timePassed = $time - $this->lastRunTime;
329
        if ($timePassed < $delay) {
330
            usleep(($delay - $timePassed) * 1000000);
331
        }
332
        $this->lastRunTime = microtime(true);
333
334
        return $callback instanceof \Closure ? $callback($this) : $callback;
335
    }
336
337
    /**
338
     * @param string $url
339
     * @param array  $data
340
     * @param bool   $isPost
341
     * @param bool   $isJson
342
     *
343
     * @throws DeCaptchaErrors
344
     *
345
     * @return string
346
     */
347
    protected function getCurlResponse($url, $data, $isPost = true, $isJson = false)
348
    {
349
        $ch = curl_init();
350
        if ($isJson) {
351
            $data = json_encode($data);
352
        } elseif (!$isPost) {
353
            $uri = [];
354
            foreach ($data as $key => $value) {
355
                $uri[] = "$key=$value";
356
            }
357
            $url .= '?'.implode('&', $uri);
358
        }
359
        curl_setopt($ch, CURLOPT_URL, $url);
360
        if (!$isJson && version_compare(PHP_VERSION, '5.5.0') >= 0 && version_compare(PHP_VERSION, '7.0') < 0 && defined('CURLOPT_SAFE_UPLOAD')) {
361
            curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
362
        }
363
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
364
        curl_setopt($ch, CURLOPT_ENCODING, 'gzip,deflate');
365
        curl_setopt($ch, CURLOPT_TIMEOUT, 30);
366
        curl_setopt($ch, CURLOPT_CONNECTTIMEOUT, 30);
367
        curl_setopt($ch, CURLOPT_POST, $isPost);
368
        if ($isPost) {
369
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
370
        }
371
        if ($isJson) {
372
            curl_setopt($ch, CURLOPT_HTTPHEADER, [
373
                'Content-Type: application/json; charset=utf-8',
374
                'Accept: application/json',
375
                'Content-Length: '.strlen($data),
376
            ]);
377
        }
378
        $result = curl_exec($ch);
379
        if (curl_errno($ch)) {
380
            throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_CURL, curl_error($ch), $this->errorLang);
381
        }
382
        curl_close($ch);
383
384
        return $result;
385
    }
386
387
    abstract public function getCode();
388
389
    abstract public function getError();
390
}
391