|
1
|
|
|
<?php |
|
2
|
|
|
|
|
3
|
|
|
namespace jumper423\decaptcha\core; |
|
4
|
|
|
|
|
5
|
|
|
use Exception; |
|
6
|
|
|
|
|
7
|
|
|
/** |
|
8
|
|
|
* Распознавание капчи. |
|
9
|
|
|
* |
|
10
|
|
|
* Class DeCaptchaBase |
|
11
|
|
|
*/ |
|
12
|
|
|
class DeCaptchaBase extends DeCaptchaAbstract implements DeCaptchaInterface |
|
13
|
|
|
{ |
|
14
|
|
|
const PARAM_FIELD_METHOD = 0; |
|
15
|
|
|
const PARAM_FIELD_KEY = 1; |
|
16
|
|
|
const PARAM_FIELD_FILE = 2; |
|
17
|
|
|
const PARAM_FIELD_PHRASE = 3; |
|
18
|
|
|
const PARAM_FIELD_REGSENSE = 4; |
|
19
|
|
|
const PARAM_FIELD_NUMERIC = 5; |
|
20
|
|
|
const PARAM_FIELD_MIN_LEN = 6; |
|
21
|
|
|
const PARAM_FIELD_MAX_LEN = 7; |
|
22
|
|
|
const PARAM_FIELD_LANGUAGE = 8; |
|
23
|
|
|
const PARAM_FIELD_SOFT_ID = 9; |
|
24
|
|
|
const PARAM_FIELD_CAPTCHA_ID = 10; |
|
25
|
|
|
const PARAM_FIELD_ACTION = 11; |
|
26
|
|
|
const PARAM_FIELD_QUESTION = 12; |
|
27
|
|
|
const PARAM_FIELD_CALC = 13; |
|
28
|
|
|
const PARAM_FIELD_HEADER_ACAO = 14; |
|
29
|
|
|
const PARAM_FIELD_TEXTINSTRUCTIONS = 15; |
|
30
|
|
|
const PARAM_FIELD_PINGBACK = 16; |
|
31
|
|
|
|
|
32
|
|
|
const ACTION_RECOGNIZE = 0; |
|
33
|
|
|
const ACTION_UNIVERSAL = 1; |
|
34
|
|
|
const ACTION_UNIVERSAL_WITH_CAPTCHA = 2; |
|
35
|
|
|
|
|
36
|
|
|
protected $paramsNames = [ |
|
37
|
|
|
self::PARAM_FIELD_METHOD => 'method', |
|
38
|
|
|
self::PARAM_FIELD_KEY => 'key', |
|
39
|
|
|
self::PARAM_FIELD_FILE => 'file', |
|
40
|
|
|
self::PARAM_FIELD_PHRASE => 'phrase', |
|
41
|
|
|
self::PARAM_FIELD_REGSENSE => 'regsense', |
|
42
|
|
|
self::PARAM_FIELD_NUMERIC => 'numeric', |
|
43
|
|
|
self::PARAM_FIELD_MIN_LEN => 'min_len', |
|
44
|
|
|
self::PARAM_FIELD_MAX_LEN => 'max_len', |
|
45
|
|
|
self::PARAM_FIELD_LANGUAGE => 'language', |
|
46
|
|
|
self::PARAM_FIELD_SOFT_ID => 'soft_id', |
|
47
|
|
|
self::PARAM_FIELD_CAPTCHA_ID => 'id', |
|
48
|
|
|
self::PARAM_FIELD_ACTION => 'action', |
|
49
|
|
|
self::PARAM_FIELD_QUESTION => 'question', |
|
50
|
|
|
self::PARAM_FIELD_HEADER_ACAO => 'header_acao', |
|
51
|
|
|
self::PARAM_FIELD_TEXTINSTRUCTIONS => 'textinstructions', |
|
52
|
|
|
self::PARAM_FIELD_PINGBACK => 'pingback', |
|
53
|
|
|
]; |
|
54
|
|
|
|
|
55
|
|
|
protected $paramsSettings = [ |
|
56
|
|
|
self::ACTION_RECOGNIZE => [ |
|
57
|
|
|
self::PARAM_FIELD_METHOD => [ |
|
58
|
|
|
self::PARAM_SLUG_DEFAULT => 'post', |
|
59
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
60
|
|
|
], |
|
61
|
|
|
self::PARAM_FIELD_KEY => [ |
|
62
|
|
|
self::PARAM_SLUG_REQUIRE => true, |
|
63
|
|
|
self::PARAM_SLUG_SPEC => self::PARAM_SPEC_KEY, |
|
64
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
65
|
|
|
], |
|
66
|
|
|
self::PARAM_FIELD_FILE => [ |
|
67
|
|
|
self::PARAM_SLUG_REQUIRE => true, |
|
68
|
|
|
self::PARAM_SLUG_SPEC => self::PARAM_SPEC_FILE, |
|
69
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
70
|
|
|
], |
|
71
|
|
|
self::PARAM_FIELD_PHRASE => [ |
|
72
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
73
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
74
|
|
|
], |
|
75
|
|
|
self::PARAM_FIELD_REGSENSE => [ |
|
76
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
77
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
78
|
|
|
], |
|
79
|
|
|
self::PARAM_FIELD_NUMERIC => [ |
|
80
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
81
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
82
|
|
|
], |
|
83
|
|
|
self::PARAM_FIELD_MIN_LEN => [ |
|
84
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
85
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
86
|
|
|
], |
|
87
|
|
|
self::PARAM_FIELD_MAX_LEN => [ |
|
88
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
89
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
90
|
|
|
], |
|
91
|
|
|
self::PARAM_FIELD_LANGUAGE => [ |
|
92
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
93
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
94
|
|
|
], |
|
95
|
|
|
self::PARAM_FIELD_QUESTION => [ |
|
96
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
97
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
98
|
|
|
], |
|
99
|
|
|
self::PARAM_FIELD_CALC => [ |
|
100
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
101
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
102
|
|
|
], |
|
103
|
|
|
self::PARAM_FIELD_HEADER_ACAO => [ |
|
104
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
105
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
106
|
|
|
], |
|
107
|
|
|
self::PARAM_FIELD_TEXTINSTRUCTIONS => [ |
|
108
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
109
|
|
|
], |
|
110
|
|
|
self::PARAM_FIELD_PINGBACK => [ |
|
111
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
112
|
|
|
], |
|
113
|
|
|
self::PARAM_FIELD_SOFT_ID => [ |
|
114
|
|
|
self::PARAM_SLUG_VARIABLE => false, |
|
115
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
116
|
|
|
], |
|
117
|
|
|
], |
|
118
|
|
|
self::ACTION_UNIVERSAL => [ |
|
119
|
|
|
self::PARAM_FIELD_KEY => [ |
|
120
|
|
|
self::PARAM_SLUG_REQUIRE => true, |
|
121
|
|
|
self::PARAM_SLUG_SPEC => self::PARAM_SPEC_KEY, |
|
122
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
123
|
|
|
], |
|
124
|
|
|
self::PARAM_FIELD_ACTION => [ |
|
125
|
|
|
self::PARAM_SLUG_REQUIRE => true, |
|
126
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
127
|
|
|
], |
|
128
|
|
|
self::PARAM_FIELD_HEADER_ACAO => [ |
|
129
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
130
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
131
|
|
|
], |
|
132
|
|
|
], |
|
133
|
|
|
self::ACTION_UNIVERSAL_WITH_CAPTCHA => [ |
|
134
|
|
|
self::PARAM_FIELD_KEY => [ |
|
135
|
|
|
self::PARAM_SLUG_REQUIRE => true, |
|
136
|
|
|
self::PARAM_SLUG_SPEC => self::PARAM_SPEC_KEY, |
|
137
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
138
|
|
|
], |
|
139
|
|
|
self::PARAM_FIELD_CAPTCHA_ID => [ |
|
140
|
|
|
self::PARAM_SLUG_REQUIRE => true, |
|
141
|
|
|
self::PARAM_SLUG_SPEC => self::PARAM_SPEC_CAPTCHA, |
|
142
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
143
|
|
|
], |
|
144
|
|
|
self::PARAM_FIELD_ACTION => [ |
|
145
|
|
|
self::PARAM_SLUG_REQUIRE => true, |
|
146
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_STRING, |
|
147
|
|
|
], |
|
148
|
|
|
self::PARAM_FIELD_HEADER_ACAO => [ |
|
149
|
|
|
self::PARAM_SLUG_DEFAULT => 0, |
|
150
|
|
|
self::PARAM_SLUG_TYPE => self::PARAM_FIELD_TYPE_INTEGER, |
|
151
|
|
|
], |
|
152
|
|
|
], |
|
153
|
|
|
]; |
|
154
|
|
|
|
|
155
|
|
|
protected $code; |
|
156
|
|
|
|
|
157
|
|
|
protected $limitSettings = [ |
|
158
|
|
|
self::ACTION_RECOGNIZE => 3, |
|
159
|
|
|
self::ACTION_UNIVERSAL_WITH_CAPTCHA => 20, |
|
160
|
|
|
]; |
|
161
|
|
|
|
|
162
|
|
|
protected $limit = []; |
|
163
|
|
|
|
|
164
|
|
|
protected function clearLimit(){ |
|
165
|
|
|
foreach ($this->limitSettings as $action => $value) { |
|
166
|
|
|
$this->limit[$action] = $value; |
|
167
|
|
|
} |
|
168
|
|
|
} |
|
169
|
|
|
|
|
170
|
|
|
public function recognize($filePath) |
|
171
|
|
|
{ |
|
172
|
|
|
try { |
|
173
|
|
|
$this->clearLimit(); |
|
174
|
|
|
$this->setParamSpec(static::PARAM_SPEC_FILE, $this->getFilePath($filePath)); |
|
175
|
|
|
$response = $this->getCurlResponse($this->getInUrl(), $this->getParams(static::ACTION_RECOGNIZE)); |
|
176
|
|
|
$data = $this->decodeResponse(static::DECODE_ACTION_RECOGNIZE, $response); |
|
177
|
|
|
if ($data[static::DECODE_PARAM_RESPONSE] === 'OK' && !empty($data[static::DECODE_PARAM_CAPTCHA])) { |
|
178
|
|
|
$this->setParamSpec(static::PARAM_SPEC_CAPTCHA, $data[static::DECODE_PARAM_CAPTCHA]); |
|
179
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
180
|
|
|
if ($data[static::DECODE_PARAM_RESPONSE] === 'ERROR_NO_SLOT_AVAILABLE' && $this->limit[static::ACTION_RECOGNIZE] > 0) { |
|
181
|
|
|
$this->limit[static::ACTION_RECOGNIZE]--; |
|
182
|
|
|
return $this->recognize($filePath); |
|
183
|
|
|
} |
|
184
|
|
|
throw new DeCaptchaErrors($data[static::DECODE_PARAM_RESPONSE]); |
|
185
|
|
|
} |
|
186
|
|
|
while ($this->limit[static::ACTION_UNIVERSAL_WITH_CAPTCHA] > 0) { |
|
187
|
|
|
$response = $this->getResponse(static::ACTION_UNIVERSAL_WITH_CAPTCHA); |
|
188
|
|
|
$data = $this->decodeResponse(static::DECODE_ACTION_GET, $response); |
|
189
|
|
|
if ($data[static::DECODE_PARAM_RESPONSE] === 'OK' && !empty($data[static::DECODE_PARAM_CODE])) { |
|
190
|
|
|
$this->code = $data[static::DECODE_PARAM_CODE]; |
|
191
|
|
|
return true; |
|
192
|
|
View Code Duplication |
} else { |
|
|
|
|
|
|
193
|
|
|
$this->limit[static::ACTION_UNIVERSAL_WITH_CAPTCHA]--; |
|
194
|
|
|
if ($data[static::DECODE_PARAM_RESPONSE] === 'CAPCHA_NOT_READY' && $this->limit[static::ACTION_UNIVERSAL_WITH_CAPTCHA] > 0) { |
|
195
|
|
|
continue; |
|
196
|
|
|
} |
|
197
|
|
|
throw new DeCaptchaErrors($data[static::DECODE_PARAM_RESPONSE]); |
|
198
|
|
|
} |
|
199
|
|
|
} |
|
200
|
|
|
} catch (Exception $e) { |
|
201
|
|
|
$this->error = $e->getMessage(); |
|
|
|
|
|
|
202
|
|
|
|
|
203
|
|
|
return false; |
|
204
|
|
|
} |
|
205
|
|
|
return false; |
|
206
|
|
|
} |
|
207
|
|
|
|
|
208
|
|
|
public function getCode() |
|
209
|
|
|
{ |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
public function getError() |
|
213
|
|
|
{ |
|
214
|
|
|
} |
|
215
|
|
|
|
|
216
|
|
|
/** |
|
217
|
|
|
* Запуск распознавания капчи. |
|
218
|
|
|
* |
|
219
|
|
|
* @deprecated |
|
220
|
|
|
* |
|
221
|
|
|
* @param string $filePath Путь до файла или ссылка на него |
|
222
|
|
|
* |
|
223
|
|
|
* @return bool |
|
224
|
|
|
*/ |
|
225
|
|
|
public function run($filePath) |
|
226
|
|
|
{ |
|
227
|
|
|
return $this->recognize($filePath); |
|
228
|
|
|
} |
|
229
|
|
|
|
|
230
|
|
|
/** |
|
231
|
|
|
* Не верно распознана. |
|
232
|
|
|
*/ |
|
233
|
|
|
public function notTrue() |
|
234
|
|
|
{ |
|
235
|
|
|
$this->getResponse('reportbad'); |
|
236
|
|
|
} |
|
237
|
|
|
|
|
238
|
|
|
const DECODE_FORMAT = 0; |
|
239
|
|
|
const DECODE_ACTION = 1; |
|
240
|
|
|
const DECODE_SEPARATOR = 2; |
|
241
|
|
|
const DECODE_PARAMS = 3; |
|
242
|
|
|
const DECODE_PARAM_SETTING_MARKER = 4; |
|
243
|
|
|
|
|
244
|
|
|
const DECODE_ACTION_RECOGNIZE = 0; |
|
245
|
|
|
const DECODE_ACTION_GET = 1; |
|
246
|
|
|
|
|
247
|
|
|
const DECODE_PARAM_RESPONSE = 0; |
|
248
|
|
|
const DECODE_PARAM_CAPTCHA = 1; |
|
249
|
|
|
const DECODE_PARAM_CODE = 2; |
|
250
|
|
|
|
|
251
|
|
|
protected $decodeSettings = [ |
|
252
|
|
|
self::DECODE_FORMAT => self::RESPONSE_TYPE_STRING, |
|
253
|
|
|
self::DECODE_ACTION => [ |
|
254
|
|
|
self::DECODE_ACTION_RECOGNIZE => [ |
|
255
|
|
|
self::DECODE_SEPARATOR => '|', |
|
256
|
|
|
self::DECODE_PARAMS => [ |
|
257
|
|
|
self::DECODE_PARAM_RESPONSE => [ |
|
258
|
|
|
self::DECODE_PARAM_SETTING_MARKER => 0, |
|
259
|
|
|
], |
|
260
|
|
|
self::DECODE_PARAM_CAPTCHA => [ |
|
261
|
|
|
self::DECODE_PARAM_SETTING_MARKER => 1, |
|
262
|
|
|
], |
|
263
|
|
|
], |
|
264
|
|
|
], |
|
265
|
|
|
self::DECODE_ACTION_GET => [ |
|
266
|
|
|
self::DECODE_SEPARATOR => '|', |
|
267
|
|
|
self::DECODE_PARAMS => [ |
|
268
|
|
|
self::DECODE_PARAM_RESPONSE => [ |
|
269
|
|
|
self::DECODE_PARAM_SETTING_MARKER => 0, |
|
270
|
|
|
], |
|
271
|
|
|
self::DECODE_PARAM_CODE => [ |
|
272
|
|
|
self::DECODE_PARAM_SETTING_MARKER => 1, |
|
273
|
|
|
], |
|
274
|
|
|
], |
|
275
|
|
|
], |
|
276
|
|
|
], |
|
277
|
|
|
]; |
|
278
|
|
|
|
|
279
|
|
|
protected function decodeResponse($action, $data) |
|
280
|
|
|
{ |
|
281
|
|
|
if (!array_key_exists($action, $this->decodeSettings[static::DECODE_ACTION])) { |
|
282
|
|
|
throw new DeCaptchaErrors('нет action'); |
|
283
|
|
|
} |
|
284
|
|
|
$decodeSetting = $this->decodeSettings[static::DECODE_ACTION][$action]; |
|
285
|
|
|
$decodeFormat = array_key_exists(static::DECODE_FORMAT, $decodeSetting) ? |
|
286
|
|
|
$decodeSetting[static::DECODE_FORMAT] : |
|
287
|
|
|
$this->decodeSettings[static::DECODE_FORMAT]; |
|
288
|
|
|
$values = []; |
|
289
|
|
|
switch ($decodeFormat) { |
|
290
|
|
|
case static::RESPONSE_TYPE_STRING: |
|
291
|
|
|
foreach (explode($decodeFormat[static::DECODE_SEPARATOR], $data) as $key => $value) { |
|
292
|
|
|
foreach ($decodeFormat[static::DECODE_PARAMS] as $param => $paramKey) { |
|
293
|
|
|
if ($key === $paramKey) { |
|
294
|
|
|
$values[$param] = $value; |
|
295
|
|
|
} |
|
296
|
|
|
} |
|
297
|
|
|
} |
|
298
|
|
|
break; |
|
299
|
|
|
} |
|
300
|
|
|
|
|
301
|
|
|
return $values; |
|
302
|
|
|
} |
|
303
|
|
|
} |
|
304
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.