Completed
Push — master ( 680248...e72f98 )
by Владислав
02:14
created

DeCaptchaAbstract::getCode()

Size

Total Lines 1

Duplication

Lines 0
Ratio 0 %

Importance

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