Completed
Push — master ( 3ca176...1b2649 )
by Владислав
02:00
created

DeCaptchaBase::clearLimit()   A

Complexity

Conditions 2
Paths 2

Size

Total Lines 6
Code Lines 3

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
dl 0
loc 6
rs 9.4285
c 0
b 0
f 0
cc 2
eloc 3
nc 2
nop 0
1
<?php
2
3
namespace jumper423\decaptcha\core;
4
5
/**
6
 * Распознавание капчи.
7
 *
8
 * Class DeCaptchaBase
9
 */
10
class DeCaptchaBase extends DeCaptchaAbstract implements DeCaptchaInterface
11
{
12
    const PARAM_FIELD_METHOD = 0;
13
    const PARAM_FIELD_KEY = 1;
14
    const PARAM_FIELD_FILE = 2;
15
    const PARAM_FIELD_PHRASE = 3;
16
    const PARAM_FIELD_REGSENSE = 4;
17
    const PARAM_FIELD_NUMERIC = 5;
18
    const PARAM_FIELD_MIN_LEN = 6;
19
    const PARAM_FIELD_MAX_LEN = 7;
20
    const PARAM_FIELD_LANGUAGE = 8;
21
    const PARAM_FIELD_SOFT_ID = 9;
22
    const PARAM_FIELD_CAPTCHA_ID = 10;
23
    const PARAM_FIELD_ACTION = 11;
24
    const PARAM_FIELD_QUESTION = 12;
25
    const PARAM_FIELD_CALC = 13;
26
    const PARAM_FIELD_HEADER_ACAO = 14;
27
    const PARAM_FIELD_TEXTINSTRUCTIONS = 15;
28
    const PARAM_FIELD_PINGBACK = 16;
29
30
    const ACTION_RECOGNIZE = 0;
31
    const ACTION_UNIVERSAL = 1;
32
    const ACTION_UNIVERSAL_WITH_CAPTCHA = 2;
33
34
    protected $paramsNames = [
35
        self::PARAM_FIELD_METHOD               => 'method',
36
        self::PARAM_FIELD_KEY                  => 'key',
37
        self::PARAM_FIELD_FILE                 => 'file',
38
        self::PARAM_FIELD_PHRASE               => 'phrase',
39
        self::PARAM_FIELD_REGSENSE             => 'regsense',
40
        self::PARAM_FIELD_NUMERIC              => 'numeric',
41
        self::PARAM_FIELD_MIN_LEN              => 'min_len',
42
        self::PARAM_FIELD_MAX_LEN              => 'max_len',
43
        self::PARAM_FIELD_LANGUAGE             => 'language',
44
        self::PARAM_FIELD_SOFT_ID              => 'soft_id',
45
        self::PARAM_FIELD_CAPTCHA_ID           => 'id',
46
        self::PARAM_FIELD_ACTION               => 'action',
47
        self::PARAM_FIELD_QUESTION             => 'question',
48
        self::PARAM_FIELD_HEADER_ACAO          => 'header_acao',
49
        self::PARAM_FIELD_TEXTINSTRUCTIONS     => 'textinstructions',
50
        self::PARAM_FIELD_PINGBACK             => 'pingback',
51
    ];
52
53
    protected $paramsSettings = [
54
        self::ACTION_RECOGNIZE => [
55
            self::PARAM_FIELD_METHOD => [
56
                self::PARAM_SLUG_DEFAULT => 'post',
57
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
58
            ],
59
            self::PARAM_FIELD_KEY => [
60
                self::PARAM_SLUG_REQUIRE => true,
61
                self::PARAM_SLUG_SPEC    => self::PARAM_SPEC_KEY,
62
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
63
            ],
64
            self::PARAM_FIELD_FILE => [
65
                self::PARAM_SLUG_REQUIRE => true,
66
                self::PARAM_SLUG_SPEC    => self::PARAM_SPEC_FILE,
67
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
68
            ],
69
            self::PARAM_FIELD_PHRASE => [
70
                self::PARAM_SLUG_DEFAULT => 0,
71
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
72
            ],
73
            self::PARAM_FIELD_REGSENSE => [
74
                self::PARAM_SLUG_DEFAULT => 0,
75
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
76
            ],
77
            self::PARAM_FIELD_NUMERIC => [
78
                self::PARAM_SLUG_DEFAULT => 0,
79
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
80
            ],
81
            self::PARAM_FIELD_MIN_LEN => [
82
                self::PARAM_SLUG_DEFAULT => 0,
83
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
84
            ],
85
            self::PARAM_FIELD_MAX_LEN => [
86
                self::PARAM_SLUG_DEFAULT => 0,
87
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
88
            ],
89
            self::PARAM_FIELD_LANGUAGE => [
90
                self::PARAM_SLUG_DEFAULT => 0,
91
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
92
            ],
93
            self::PARAM_FIELD_QUESTION => [
94
                self::PARAM_SLUG_DEFAULT => 0,
95
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
96
            ],
97
            self::PARAM_FIELD_CALC => [
98
                self::PARAM_SLUG_DEFAULT => 0,
99
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
100
            ],
101
            self::PARAM_FIELD_HEADER_ACAO => [
102
                self::PARAM_SLUG_DEFAULT => 0,
103
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
104
            ],
105
            self::PARAM_FIELD_TEXTINSTRUCTIONS => [
106
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
107
            ],
108
            self::PARAM_FIELD_PINGBACK => [
109
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
110
            ],
111
            self::PARAM_FIELD_SOFT_ID => [
112
                self::PARAM_SLUG_VARIABLE => false,
113
                self::PARAM_SLUG_TYPE     => self::PARAM_FIELD_TYPE_INTEGER,
114
            ],
115
        ],
116
        self::ACTION_UNIVERSAL => [
117
            self::PARAM_FIELD_KEY => [
118
                self::PARAM_SLUG_REQUIRE => true,
119
                self::PARAM_SLUG_SPEC    => self::PARAM_SPEC_KEY,
120
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
121
            ],
122
            self::PARAM_FIELD_ACTION => [
123
                self::PARAM_SLUG_REQUIRE => true,
124
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
125
            ],
126
            self::PARAM_FIELD_HEADER_ACAO => [
127
                self::PARAM_SLUG_DEFAULT => 0,
128
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
129
            ],
130
        ],
131
        self::ACTION_UNIVERSAL_WITH_CAPTCHA => [
132
            self::PARAM_FIELD_KEY => [
133
                self::PARAM_SLUG_REQUIRE => true,
134
                self::PARAM_SLUG_SPEC    => self::PARAM_SPEC_KEY,
135
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
136
            ],
137
            self::PARAM_FIELD_CAPTCHA_ID => [
138
                self::PARAM_SLUG_REQUIRE => true,
139
                self::PARAM_SLUG_SPEC    => self::PARAM_SPEC_CAPTCHA,
140
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
141
            ],
142
            self::PARAM_FIELD_ACTION => [
143
                self::PARAM_SLUG_REQUIRE => true,
144
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_STRING,
145
            ],
146
            self::PARAM_FIELD_HEADER_ACAO => [
147
                self::PARAM_SLUG_DEFAULT => 0,
148
                self::PARAM_SLUG_TYPE    => self::PARAM_FIELD_TYPE_INTEGER,
149
            ],
150
        ],
151
    ];
152
153
    protected $code;
154
155
    protected $limitSettings = [
156
        self::ACTION_RECOGNIZE              => 3,
157
        self::ACTION_UNIVERSAL_WITH_CAPTCHA => 20,
158
    ];
159
160
    protected $limit = [];
161
162
    protected function resetLimits()
163
    {
164
        foreach ($this->limitSettings as $action => $value) {
165
            $this->limit[$action] = $value;
166
        }
167
    }
168
169
    protected function limitHasNotYetEnded($action)
170
    {
171
        return $this->limit[$action]-- > 0;
172
    }
173
174
    const RESPONSE_RECOGNIZE_OK = 'OK';
175
    const RESPONSE_RECOGNIZE_REPEAT = 'ERROR_NO_SLOT_AVAILABLE';
176
    const RESPONSE_GET_OK = 'OK';
177
    const RESPONSE_GET_REPEAT = 'CAPCHA_NOT_READY';
178
179
    const SLEEP_RECOGNIZE = 5;
180
    const SLEEP_GET = 2;
181
    const SLEEP_BETWEEN = 5;
182
183
    public function recognize($filePath)
184
    {
185
        try {
186
            $this->resetLimits();
187
            $this->setParamSpec(static::PARAM_SPEC_FILE, $this->getFilePath($filePath));
188
            return $this->requestRecognize() && $this->requestCode();
189
        } catch (DeCaptchaErrors $e) {
190
            $this->error = $e->getMessage();
0 ignored issues
show
Bug introduced by
The property error does not exist. Did you maybe forget to declare it?

In PHP it is possible to write to properties without declaring them. For example, the following is perfectly valid PHP code:

class MyClass { }

$x = new MyClass();
$x->foo = true;

Generally, it is a good practice to explictly declare properties to avoid accidental typos and provide IDE auto-completion:

class MyClass {
    public $foo;
}

$x = new MyClass();
$x->foo = true;
Loading history...
191
            return false;
192
        }
193
    }
194
195
    protected function requestRecognize()
196
    {
197
        while ($this->limitHasNotYetEnded(static::ACTION_RECOGNIZE)) {
198
            $this->executionDelayed(static::SLEEP_RECOGNIZE);
199
            $response = $this->getCurlResponse($this->getInUrl(), $this->getParams(static::ACTION_RECOGNIZE));
200
            $dataRecognize = $this->decodeResponse(static::DECODE_ACTION_RECOGNIZE, $response);
201
            if ($dataRecognize[static::DECODE_PARAM_RESPONSE] === static::RESPONSE_RECOGNIZE_OK && !empty($dataRecognize[static::DECODE_PARAM_CAPTCHA])) {
202
                $this->setParamSpec(static::PARAM_SPEC_CAPTCHA, $dataRecognize[static::DECODE_PARAM_CAPTCHA]);
203
                $this->executionDelayed(static::SLEEP_BETWEEN);
204
205
                return true;
206
            } elseif ($dataRecognize[static::DECODE_PARAM_RESPONSE] === static::RESPONSE_RECOGNIZE_REPEAT) {
207
                continue;
208
            }
209
            throw new DeCaptchaErrors($dataRecognize[static::DECODE_PARAM_RESPONSE]);
210
        }
211
        throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_LIMIT);
212
    }
213
214
    protected function requestCode()
215
    {
216
        while ($this->limitHasNotYetEnded(static::ACTION_UNIVERSAL_WITH_CAPTCHA)) {
217
            $this->executionDelayed(static::SLEEP_GET);
218
            $response = $this->getResponse(static::ACTION_UNIVERSAL_WITH_CAPTCHA);
219
            $dataGet = $this->decodeResponse(static::DECODE_ACTION_GET, $response);
220
            if ($dataGet[static::DECODE_PARAM_RESPONSE] === static::RESPONSE_GET_OK && !empty($dataGet[static::DECODE_PARAM_CODE])) {
221
                $this->code = $dataGet[static::DECODE_PARAM_CODE];
222
223
                return true;
224
            } elseif ($dataGet[static::DECODE_PARAM_RESPONSE] === static::RESPONSE_GET_REPEAT) {
225
                continue;
226
            }
227
            throw new DeCaptchaErrors($dataGet[static::DECODE_PARAM_RESPONSE]);
228
        }
229
        throw new DeCaptchaErrors(DeCaptchaErrors::ERROR_LIMIT);
230
    }
231
232
    public function getCode()
233
    {
234
    }
235
236
    public function getError()
237
    {
238
    }
239
240
    /**
241
     * Запуск распознавания капчи.
242
     *
243
     * @deprecated
244
     *
245
     * @param string $filePath Путь до файла или ссылка на него
246
     *
247
     * @return bool
248
     */
249
    public function run($filePath)
250
    {
251
        return $this->recognize($filePath);
252
    }
253
254
    /**
255
     * Не верно распознана.
256
     */
257
    public function notTrue()
258
    {
259
        $this->getResponse('reportbad');
260
    }
261
262
    const DECODE_FORMAT = 0;
263
    const DECODE_ACTION = 1;
264
    const DECODE_SEPARATOR = 2;
265
    const DECODE_PARAMS = 3;
266
    const DECODE_PARAM_SETTING_MARKER = 4;
267
268
    const DECODE_ACTION_RECOGNIZE = 0;
269
    const DECODE_ACTION_GET = 1;
270
271
    const DECODE_PARAM_RESPONSE = 0;
272
    const DECODE_PARAM_CAPTCHA = 1;
273
    const DECODE_PARAM_CODE = 2;
274
275
    protected $decodeSettings = [
276
        self::DECODE_FORMAT => self::RESPONSE_TYPE_STRING,
277
        self::DECODE_ACTION => [
278
            self::DECODE_ACTION_RECOGNIZE => [
279
                self::DECODE_SEPARATOR => '|',
280
                self::DECODE_PARAMS    => [
281
                    self::DECODE_PARAM_RESPONSE => [
282
                        self::DECODE_PARAM_SETTING_MARKER => 0,
283
                    ],
284
                    self::DECODE_PARAM_CAPTCHA => [
285
                        self::DECODE_PARAM_SETTING_MARKER => 1,
286
                    ],
287
                ],
288
            ],
289
            self::DECODE_ACTION_GET => [
290
                self::DECODE_SEPARATOR => '|',
291
                self::DECODE_PARAMS    => [
292
                    self::DECODE_PARAM_RESPONSE => [
293
                        self::DECODE_PARAM_SETTING_MARKER => 0,
294
                    ],
295
                    self::DECODE_PARAM_CODE => [
296
                        self::DECODE_PARAM_SETTING_MARKER => 1,
297
                    ],
298
                ],
299
            ],
300
        ],
301
    ];
302
303
    protected function decodeResponse($action, $data)
304
    {
305
        if (!array_key_exists($action, $this->decodeSettings[static::DECODE_ACTION])) {
306
            throw new DeCaptchaErrors('нет action');
307
        }
308
        $decodeSetting = $this->decodeSettings[static::DECODE_ACTION][$action];
309
        $decodeFormat = array_key_exists(static::DECODE_FORMAT, $decodeSetting) ?
310
            $decodeSetting[static::DECODE_FORMAT] :
311
            $this->decodeSettings[static::DECODE_FORMAT];
312
        $values = [];
313
        switch ($decodeFormat) {
314
            case static::RESPONSE_TYPE_STRING:
315
                foreach (explode($decodeFormat[static::DECODE_SEPARATOR], $data) as $key => $value) {
316
                    foreach ($decodeFormat[static::DECODE_PARAMS] as $param => $paramKey) {
317
                        if ($key === $paramKey) {
318
                            $values[$param] = $value;
319
                        }
320
                    }
321
                }
322
                break;
323
        }
324
325
        return $values;
326
    }
327
}
328