Completed
Push — master ( 75ca6a...d59674 )
by Владислав
02:12
created

DeCaptchaAbstract::setParam()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 1
CRAP Score 1

Importance

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