Completed
Push — master ( d1e8ce...92efb6 )
by Владислав
02:21
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
31
    const PARAM_SLUG_DEFAULT = 0;
32
    const PARAM_SLUG_TYPE = 1;
33
    const PARAM_SLUG_REQUIRE = 2;
34
    const PARAM_SLUG_SPEC = 3;
35
    const PARAM_SLUG_VARIABLE = 4;
36
37
    const PARAM_SPEC_KEY = 0;
38
    const PARAM_SPEC_FILE = 1;
39
    const PARAM_SPEC_CAPTCHA = 2;
40
    const PARAM_SPEC_CODE = 3;
41
42
    /**
43
     * Сервис на который будем загружать капчу.
44
     *
45
     * @var string
46
     */
47
    protected $domain;
48
    protected $errorLang = DeCaptchaErrors::LANG_EN;
49
    protected $lastRunTime = null;
50
    /** @var DeCaptchaErrors */
51
    protected $errorObject;
52
    protected $causeAnError = false;
53
54
    protected $limit = [];
55
    protected $paramsSpec = [];
56
    protected $params = [];
57
    protected $limitSettings = [];
58
    protected $decodeSettings = [];
59
    protected $actions = [];
60
    protected $paramsNames = [];
61
62
    protected function resetLimits()
63
    {
64
        foreach ($this->limitSettings as $action => $value) {
65
            $this->limit[$action] = $value;
66
        }
67
    }
68
69
    protected function limitHasNotYetEnded($action)
70
    {
71
        return $this->limit[$action]-- > 0;
72
    }
73
74
    /**
75
     * Запуск распознавания капчи.
76
     *
77
     * @deprecated
78
     *
79
     * @param string $filePath Путь до файла или ссылка на него
80
     *
81
     * @return bool
82
     */
83
    public function run($filePath)
84
    {
85
        return $this->recognize($filePath);
86
    }
87
88
    /**
89
     * Не верно распознана.
90
     */
91
    public function notTrue()
92 3
    {
93
        $this->getResponse('reportbad');
94 3
    }
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($decodeFormat[static::DECODE_SEPARATOR], $data) as $key => $value) {
109
                    foreach ($decodeFormat[static::DECODE_PARAMS] as $param => $paramKey) {
110
                        if ($key === $paramKey) {
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
    public function setErrorLang($errorLang)
122
    {
123
        $this->errorLang = $errorLang;
124 1
    }
125 1
126
    /**
127 2
     * Узнаём путь до файла
128 1
     * Если передана ссылка, то скачиваем и кладём во временную директорию.
129
     *
130 1
     * @param string $fileName
131
     *
132
     * @throws Exception
133
     *
134
     * @return string
135
     */
136 4
    protected function getFilePath($fileName)
137 4
    {
138
        if (strpos($fileName, 'http://') !== false || strpos($fileName, 'https://') !== false) {
139
            try {
140
                $current = file_get_contents($fileName);
141
            } catch (\Exception $e) {
142
                throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_FILE_IS_NOT_LOADED, $fileName, $this->errorLang);
143
            }
144 2
            $path = tempnam(sys_get_temp_dir(), 'captcha');
145 2
            file_put_contents($path, $current);
146
147
            return $path;
148
        }
149
        if (file_exists($fileName)) {
150
            return $fileName;
151
        }
152 1
        throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_FILE_NOT_FOUND, $fileName, $this->errorLang);
153 1
    }
154
155
    /**
156
     * @param $action
157
     *
158
     * @return string
159 1
     */
160 1
    protected function getActionUrl($action)
161
    {
162
        return $this->getBaseUrl() . $this->actions[$action][static::ACTION_URI];
163
    }
164
165
    /**
166
     * @return string
167
     */
168
    protected function getBaseUrl()
169 2
    {
170
        return "http://{$this->domain}/";
171 2
    }
172 1
173
    public function setParams($params)
174 1
    {
175
        if (is_array($params)) {
176
            foreach ($params as $param => $value) {
177
                $this->params[$param] = $value;
178
            }
179
        }
180
    }
181
182
    public function setParamSpec($param, $value)
183
    {
184
        $this->paramsSpec[$param] = $value;
185 1
    }
186 1
187 1
    public function getParamSpec($param)
188 1
    {
189 1
        if (!array_key_exists($param, $this->paramsSpec) || is_null($this->paramsSpec[$param])) {
190 1
            return null;
191 1
        }
192 1
        switch ($param) {
193
            case static::PARAM_SPEC_FILE:
194
                return (version_compare(PHP_VERSION, '5.5.0') >= 0) ? new \CURLFile($this->paramsSpec[$param]) : '@' . $this->paramsSpec[$param];
195
            case static::PARAM_SPEC_KEY:
196
                return is_callable($this->paramsSpec[$param]) ? $this->paramsSpec[$param]() : $this->paramsSpec[$param];
197
            case static::PARAM_SPEC_CAPTCHA:
198
            case static::PARAM_SPEC_CODE:
199
                return $this->paramsSpec[$param];
200
        }
201
202
        return null;
203
    }
204
205
    protected function getParams($action)
206
    {
207
        if (empty($this->actions[$action])) {
208
            return [];
209
        }
210
        $params = [];
211
        foreach ($this->actions[$action][static::ACTION_FIELDS] as $field => $settings) {
212
            $value = null;
213
            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))) {
214
                $value = $this->params[$field];
215
            }
216
            if (array_key_exists(self::PARAM_SLUG_DEFAULT, $settings)) {
217
                $value = $settings[self::PARAM_SLUG_DEFAULT];
218
            }
219
            if (array_key_exists(self::PARAM_SLUG_SPEC, $settings) && array_key_exists($settings[self::PARAM_SLUG_SPEC], $this->paramsSpec)) {
220
                $value = $this->getParamSpec($settings[self::PARAM_SLUG_SPEC]);
221
            }
222
            if (array_key_exists(self::PARAM_SLUG_REQUIRE, $settings) && $settings[self::PARAM_SLUG_REQUIRE] === true && is_null($value)) {
223
                throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_PARAM_REQUIRE, array_key_exists($field, $this->paramsNames) ? $this->paramsNames[$field] : $field, $this->errorLang);
224
            }
225
            if (array_key_exists($field, $this->paramsNames)) {
226
                switch ($settings[self::PARAM_SLUG_TYPE]) {
227
                    case self::PARAM_FIELD_TYPE_INTEGER:
228
                        $params[$this->paramsNames[$field]] = (int)$value;
229
                        break;
230
                    case self::PARAM_FIELD_TYPE_STRING:
231
                        $params[$this->paramsNames[$field]] = (string)$value;
232
                        break;
233
                }
234
            }
235
        }
236
237
        return $params;
238
    }
239
240
    /**
241
     * @param string $action
242
     *
243
     * @return string
244
     */
245
    protected function getResponse($action)
246
    {
247
        return $this->getCurlResponse($this->getActionUrl($action), $this->getParams($action), $this->actions[$action][static::ACTION_METHOD] === static::ACTION_METHOD_POST);
248
    }
249
250
    /**
251
     * Задержка выполнения.
252
     *
253
     * @param int $delay Количество секунд
254
     * @param \Closure|null $callback
255
     *
256
     * @return mixed
257
     */
258
    protected function executionDelayed($delay = 0, $callback = null)
259
    {
260
        $time = microtime(true);
261
        $timePassed = $time - $this->lastRunTime;
262
        if ($timePassed < $delay) {
263
            usleep(($delay - $timePassed) * 1000000);
264
        }
265
        $this->lastRunTime = microtime(true);
266
267
        return $callback instanceof \Closure ? $callback($this) : $callback;
268
    }
269
270
    /**
271
     * @param string $url
272
     * @param $data
273
     * @param $isPost
274
     *
275
     * @throws DeCaptchaErrors
276
     *
277
     * @return mixed
278
     */
279
    protected function getCurlResponse($url, $data, $isPost = true)
280
    {
281
        $ch = curl_init();
282
        if ($isPost) {
283
            curl_setopt($ch, CURLOPT_POSTFIELDS, $data);
284
        } else {
285
            $uri = [];
286
            foreach ($data as $key => $value) {
287
                $uri[] = "$key=$value";
288
            }
289
            $url .= '?' . implode('&', $uri);
290
        }
291
        curl_setopt($ch, CURLOPT_URL, $url);
292
        if (version_compare(PHP_VERSION, '5.5.0') >= 0 && version_compare(PHP_VERSION, '7.0') < 0 && defined('CURLOPT_SAFE_UPLOAD')) {
293
            curl_setopt($ch, CURLOPT_SAFE_UPLOAD, false);
294
        }
295
        curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
296
        curl_setopt($ch, CURLOPT_TIMEOUT, 60);
297
        curl_setopt($ch, CURLOPT_POST, $isPost);
298
        $result = curl_exec($ch);
299
        if (curl_errno($ch)) {
300
            throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_CURL, curl_error($ch), $this->errorLang);
301
        }
302
        curl_close($ch);
303
304
        return $result;
305
    }
306
307
    abstract public function recognize($filePath);
308
309
    abstract public function getCode();
310
311
    abstract public function getError();
312
}
313