Completed
Push — master ( 7e805b...605ef1 )
by Владислав
17:05 queued 14:18
created

DeCaptchaAbstract::getParams()   D

Complexity

Conditions 23
Paths 211

Size

Total Lines 51
Code Lines 37

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 552

Importance

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