Completed
Push — master ( 570f1a...76d1b8 )
by Владислав
02:10
created

DeCaptchaAbstract::run()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4
Code Lines 2

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

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