|
1
|
|
|
<?php |
|
2
|
|
|
namespace PHPDaemon\Clients\MySQL; |
|
3
|
|
|
|
|
4
|
|
|
use PHPDaemon\Core\Daemon; |
|
5
|
|
|
use PHPDaemon\Network\ClientConnection; |
|
6
|
|
|
use PHPDaemon\Structures\StackCallbacks; |
|
7
|
|
|
use PHPDaemon\Utils\Binary; |
|
8
|
|
|
|
|
9
|
|
|
class Connection extends ClientConnection |
|
10
|
|
|
{ |
|
11
|
|
|
|
|
12
|
|
|
/** |
|
13
|
|
|
* @var integer Sequence. Pointer of packet sequence |
|
14
|
|
|
*/ |
|
15
|
|
|
public $seq = 0; |
|
16
|
|
|
|
|
17
|
|
|
/** |
|
18
|
|
|
* @var integer Client flags |
|
19
|
|
|
*/ |
|
20
|
|
|
public $clientFlags = 239237; |
|
21
|
|
|
|
|
22
|
|
|
/** |
|
23
|
|
|
* @var integer |
|
24
|
|
|
*/ |
|
25
|
|
|
public $threadId; |
|
26
|
|
|
|
|
27
|
|
|
/** |
|
28
|
|
|
* @var string |
|
29
|
|
|
*/ |
|
30
|
|
|
public $scramble; |
|
31
|
|
|
|
|
32
|
|
|
/** |
|
33
|
|
|
* @var string |
|
34
|
|
|
*/ |
|
35
|
|
|
public $serverver; |
|
36
|
|
|
|
|
37
|
|
|
/** |
|
38
|
|
|
* @var integer |
|
39
|
|
|
*/ |
|
40
|
|
|
public $serverCaps; |
|
41
|
|
|
|
|
42
|
|
|
/** |
|
43
|
|
|
* @var integer |
|
44
|
|
|
*/ |
|
45
|
|
|
public $serverLang; |
|
46
|
|
|
|
|
47
|
|
|
/** |
|
48
|
|
|
* @var integer Server flags: http://dev.mysql.com/doc/internals/en/status-flags.html |
|
49
|
|
|
*/ |
|
50
|
|
|
public $serverStatus; |
|
51
|
|
|
|
|
52
|
|
|
/** |
|
53
|
|
|
* @var integer Number of warnings generated by the command |
|
54
|
|
|
*/ |
|
55
|
|
|
public $warnCount; |
|
56
|
|
|
|
|
57
|
|
|
/** |
|
58
|
|
|
* @var string |
|
59
|
|
|
*/ |
|
60
|
|
|
public $message; |
|
61
|
|
|
|
|
62
|
|
|
/** |
|
63
|
|
|
* @var integer Charset number (see MySQL charset list) |
|
64
|
|
|
*/ |
|
65
|
|
|
public $charsetNumber = 0x21; |
|
66
|
|
|
|
|
67
|
|
|
/** |
|
68
|
|
|
* @var string User name |
|
69
|
|
|
*/ |
|
70
|
|
|
protected $user = 'root'; |
|
71
|
|
|
|
|
72
|
|
|
/** |
|
73
|
|
|
* @var string Password |
|
74
|
|
|
*/ |
|
75
|
|
|
protected $password = ''; |
|
76
|
|
|
|
|
77
|
|
|
/** |
|
78
|
|
|
* @var string Database name |
|
79
|
|
|
*/ |
|
80
|
|
|
public $dbname = ''; |
|
81
|
|
|
|
|
82
|
|
|
/** |
|
83
|
|
|
* @TODO DESCR |
|
84
|
|
|
*/ |
|
85
|
|
|
const STATE_STANDBY = 0; |
|
86
|
|
|
|
|
87
|
|
|
/** |
|
88
|
|
|
* @TODO DESCR |
|
89
|
|
|
*/ |
|
90
|
|
|
const STATE_BODY = 1; |
|
91
|
|
|
|
|
92
|
|
|
/** |
|
93
|
|
|
* @var string Phase |
|
94
|
|
|
*/ |
|
95
|
|
|
protected $phase = 0; |
|
96
|
|
|
|
|
97
|
|
|
/** |
|
98
|
|
|
* @TODO DESCR |
|
99
|
|
|
*/ |
|
100
|
|
|
const PHASE_GOT_INIT = 1; |
|
101
|
|
|
|
|
102
|
|
|
/** |
|
103
|
|
|
* @TODO DESCR |
|
104
|
|
|
*/ |
|
105
|
|
|
const PHASE_AUTH_SENT = 2; |
|
106
|
|
|
|
|
107
|
|
|
/** |
|
108
|
|
|
* @TODO DESCR |
|
109
|
|
|
*/ |
|
110
|
|
|
const PHASE_AUTH_ERR = 3; |
|
111
|
|
|
|
|
112
|
|
|
/** |
|
113
|
|
|
* @TODO DESCR |
|
114
|
|
|
*/ |
|
115
|
|
|
const PHASE_HANDSHAKED = 4; |
|
116
|
|
|
|
|
117
|
|
|
/** |
|
118
|
|
|
* @var integer State of pointer of incoming data. 0 - Result Set Header Packet, 1 - Field Packet, 2 - Row Packet |
|
119
|
|
|
*/ |
|
120
|
|
|
protected $rsState = 0; |
|
121
|
|
|
|
|
122
|
|
|
/** |
|
123
|
|
|
* @TODO DESCR |
|
124
|
|
|
*/ |
|
125
|
|
|
const RS_STATE_HEADER = 0; |
|
126
|
|
|
|
|
127
|
|
|
/** |
|
128
|
|
|
* @TODO DESCR |
|
129
|
|
|
*/ |
|
130
|
|
|
const RS_STATE_FIELD = 1; |
|
131
|
|
|
|
|
132
|
|
|
/** |
|
133
|
|
|
* @TODO DESCR |
|
134
|
|
|
*/ |
|
135
|
|
|
const RS_STATE_ROW = 2; |
|
136
|
|
|
|
|
137
|
|
|
/** |
|
138
|
|
|
* @var integer Packet size |
|
139
|
|
|
*/ |
|
140
|
|
|
protected $pctSize = 0; |
|
141
|
|
|
|
|
142
|
|
|
/** |
|
143
|
|
|
* @var array Result rows |
|
144
|
|
|
*/ |
|
145
|
|
|
public $resultRows = []; |
|
146
|
|
|
|
|
147
|
|
|
/** |
|
148
|
|
|
* @var array Result fields |
|
149
|
|
|
*/ |
|
150
|
|
|
public $resultFields = []; |
|
151
|
|
|
|
|
152
|
|
|
/** |
|
153
|
|
|
* @var object Property holds a reference to user's object |
|
154
|
|
|
*/ |
|
155
|
|
|
public $context; |
|
156
|
|
|
|
|
157
|
|
|
/** |
|
158
|
|
|
* @var integer INSERT_ID() |
|
159
|
|
|
*/ |
|
160
|
|
|
public $insertId; |
|
161
|
|
|
|
|
162
|
|
|
/** |
|
163
|
|
|
* @var integer Affected rows |
|
164
|
|
|
*/ |
|
165
|
|
|
public $affectedRows; |
|
166
|
|
|
|
|
167
|
|
|
/** |
|
168
|
|
|
* @var integer Protocol version |
|
169
|
|
|
*/ |
|
170
|
|
|
public $protover = 0; |
|
171
|
|
|
|
|
172
|
|
|
/** |
|
173
|
|
|
* @var integer Timeout |
|
174
|
|
|
*/ |
|
175
|
|
|
public $timeout = 120; |
|
176
|
|
|
|
|
177
|
|
|
/** |
|
178
|
|
|
* @var integer Error number |
|
179
|
|
|
*/ |
|
180
|
|
|
public $errno = 0; |
|
181
|
|
|
|
|
182
|
|
|
/** |
|
183
|
|
|
* @var string Error message |
|
184
|
|
|
*/ |
|
185
|
|
|
public $errmsg = ''; |
|
186
|
|
|
|
|
187
|
|
|
/** |
|
188
|
|
|
* @var integer Low mark |
|
189
|
|
|
*/ |
|
190
|
|
|
protected $lowMark = 4; |
|
191
|
|
|
|
|
192
|
|
|
/** |
|
193
|
|
|
* Executes the given callback when/if the connection is handshaked |
|
194
|
|
|
* @param callable $cb Callback |
|
195
|
|
|
* @callback $cb ( Connection $conn, boolean $success ) |
|
196
|
|
|
* @return void |
|
197
|
|
|
*/ |
|
198
|
|
View Code Duplication |
public function onConnected($cb) |
|
|
|
|
|
|
199
|
|
|
{ |
|
200
|
|
|
if ($this->phase === self::PHASE_AUTH_ERR) { |
|
|
|
|
|
|
201
|
|
|
$cb($this, false); |
|
202
|
|
|
} elseif ($this->phase === self::PHASE_HANDSHAKED) { |
|
|
|
|
|
|
203
|
|
|
$cb($this, true); |
|
204
|
|
|
} else { |
|
205
|
|
|
if (!$this->onConnected) { |
|
206
|
|
|
$this->onConnected = new StackCallbacks(); |
|
207
|
|
|
} |
|
208
|
|
|
$this->onConnected->push($cb); |
|
209
|
|
|
} |
|
210
|
|
|
} |
|
211
|
|
|
|
|
212
|
|
|
/** |
|
213
|
|
|
* Called when the connection is handshaked (at low-level), and peer is ready to recv. data |
|
214
|
|
|
* @return void |
|
215
|
|
|
*/ |
|
216
|
|
|
public function onReady() |
|
217
|
|
|
{ |
|
218
|
|
|
if (mb_orig_strlen($this->path) && !mb_orig_strlen($this->dbname)) { |
|
219
|
|
|
$this->dbname = $this->path; |
|
220
|
|
|
} |
|
221
|
|
|
} |
|
222
|
|
|
|
|
223
|
|
|
/** |
|
224
|
|
|
* Sends a packet |
|
225
|
|
|
* @param string $packet Data |
|
226
|
|
|
* @return boolean Success |
|
227
|
|
|
*/ |
|
228
|
|
|
public function sendPacket($packet) |
|
229
|
|
|
{ |
|
230
|
|
|
//Daemon::log('Client --> Server: ' . Debug::exportBytes($packet) . "\n\n"); |
|
231
|
|
|
return $this->write(Binary::int2bytes(3, mb_orig_strlen($packet), true) . chr($this->seq++) . $packet); |
|
232
|
|
|
} |
|
233
|
|
|
|
|
234
|
|
|
/** |
|
235
|
|
|
* Builds length-encoded binary string |
|
236
|
|
|
* @param string $s String |
|
237
|
|
|
* @return string Resulting binary string |
|
238
|
|
|
*/ |
|
239
|
|
|
public function buildLenEncodedBinary($s) |
|
240
|
|
|
{ |
|
241
|
|
|
if ($s === null) { |
|
242
|
|
|
return "\251"; |
|
243
|
|
|
} |
|
244
|
|
|
|
|
245
|
|
|
$l = mb_orig_strlen($s); |
|
246
|
|
|
|
|
247
|
|
|
if ($l <= 250) { |
|
248
|
|
|
return chr($l) . $s; |
|
249
|
|
|
} |
|
250
|
|
|
|
|
251
|
|
|
if ($l <= 0xFFFF) { |
|
252
|
|
|
return "\252" . Binary::int2bytes(2, true) . $s; |
|
|
|
|
|
|
253
|
|
|
} |
|
254
|
|
|
|
|
255
|
|
|
if ($l <= 0xFFFFFF) { |
|
256
|
|
|
return "\254" . Binary::int2bytes(3, true) . $s; |
|
|
|
|
|
|
257
|
|
|
} |
|
258
|
|
|
|
|
259
|
|
|
return Binary::int2bytes(8, $l, true) . $s; |
|
260
|
|
|
} |
|
261
|
|
|
|
|
262
|
|
|
/** |
|
263
|
|
|
* Parses length-encoded binary integer |
|
264
|
|
|
* @return integer Result |
|
|
|
|
|
|
265
|
|
|
*/ |
|
266
|
|
|
public function parseEncodedBinary() |
|
267
|
|
|
{ |
|
268
|
|
|
$f = ord($this->read(1)); |
|
269
|
|
|
if ($f <= 250) { |
|
270
|
|
|
return $f; |
|
271
|
|
|
} |
|
272
|
|
|
if ($f === 251) { |
|
273
|
|
|
return null; |
|
274
|
|
|
} |
|
275
|
|
|
if ($f === 255) { |
|
276
|
|
|
return false; |
|
277
|
|
|
} |
|
278
|
|
|
if ($f === 252) { |
|
279
|
|
|
return Binary::bytes2int($this->read(2), true); |
|
|
|
|
|
|
280
|
|
|
} |
|
281
|
|
|
if ($f === 253) { |
|
282
|
|
|
return Binary::bytes2int($this->read(3), true); |
|
|
|
|
|
|
283
|
|
|
} |
|
284
|
|
|
return Binary::bytes2int($this->read(8), true); |
|
|
|
|
|
|
285
|
|
|
} |
|
286
|
|
|
|
|
287
|
|
|
/** |
|
288
|
|
|
* Parse length-encoded string |
|
289
|
|
|
* @return integer Result |
|
|
|
|
|
|
290
|
|
|
*/ |
|
291
|
|
|
public function parseEncodedString() |
|
292
|
|
|
{ |
|
293
|
|
|
$l = $this->parseEncodedBinary(); |
|
294
|
|
|
if (($l === null) || ($l === false)) { |
|
295
|
|
|
return $l; |
|
296
|
|
|
} |
|
297
|
|
|
return $this->read($l); |
|
298
|
|
|
} |
|
299
|
|
|
|
|
300
|
|
|
/** |
|
301
|
|
|
* Generates auth. token |
|
302
|
|
|
* @param string $scramble Scramble string |
|
303
|
|
|
* @param string $password Password |
|
304
|
|
|
* @return string Result |
|
305
|
|
|
*/ |
|
306
|
|
|
public function getAuthToken($scramble, $password) |
|
307
|
|
|
{ |
|
308
|
|
|
return sha1($scramble . sha1($hash1 = sha1($password, true), true), true) ^ $hash1; |
|
309
|
|
|
} |
|
310
|
|
|
|
|
311
|
|
|
/** |
|
312
|
|
|
* Sends auth. packet |
|
313
|
|
|
* @return void |
|
314
|
|
|
*/ |
|
315
|
|
|
public function auth() |
|
316
|
|
|
{ |
|
317
|
|
|
if ($this->phase !== self::PHASE_GOT_INIT) { |
|
|
|
|
|
|
318
|
|
|
return; |
|
319
|
|
|
} |
|
320
|
|
|
$this->phase = self::PHASE_AUTH_SENT; |
|
|
|
|
|
|
321
|
|
View Code Duplication |
$this->onResponse->push(function ($conn, $result) { |
|
|
|
|
|
|
322
|
|
|
if ($conn->onConnected) { |
|
323
|
|
|
$conn->connected = true; |
|
324
|
|
|
$conn->onConnected->executeAll($conn, $result); |
|
325
|
|
|
$conn->onConnected = null; |
|
326
|
|
|
} |
|
327
|
|
|
}); |
|
328
|
|
|
$this->clientFlags = |
|
329
|
|
|
Pool::CLIENT_LONG_PASSWORD | |
|
330
|
|
|
Pool::CLIENT_LONG_FLAG | |
|
331
|
|
|
Pool::CLIENT_LOCAL_FILES | |
|
332
|
|
|
Pool::CLIENT_PROTOCOL_41 | |
|
333
|
|
|
Pool::CLIENT_INTERACTIVE | |
|
334
|
|
|
Pool::CLIENT_TRANSACTIONS | |
|
335
|
|
|
Pool::CLIENT_SECURE_CONNECTION | |
|
336
|
|
|
Pool::CLIENT_MULTI_STATEMENTS | |
|
337
|
|
|
Pool::CLIENT_MULTI_RESULTS; |
|
338
|
|
|
|
|
339
|
|
|
$this->sendPacket( |
|
340
|
|
|
$packet = pack('VVc', $this->clientFlags, $this->pool->maxAllowedPacket, $this->charsetNumber) |
|
341
|
|
|
. "\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00\x00" |
|
342
|
|
|
. $this->user . "\x00" |
|
343
|
|
|
. ($this->password === '' ? "\x00" : $this->buildLenEncodedBinary( |
|
344
|
|
|
$this->getAuthToken($this->scramble, $this->password) |
|
345
|
|
|
)) |
|
346
|
|
|
. ($this->path !== '' ? $this->path . "\x00" : '') |
|
347
|
|
|
); |
|
348
|
|
|
} |
|
349
|
|
|
|
|
350
|
|
|
/** |
|
351
|
|
|
* Sends SQL-query |
|
352
|
|
|
* @param string $q Query |
|
353
|
|
|
* @param callable $cb Optional. Callback called when response received |
|
|
|
|
|
|
354
|
|
|
* @callback $cb ( Connection $conn, boolean $success ) |
|
355
|
|
|
* @return boolean Success |
|
356
|
|
|
*/ |
|
357
|
|
|
public function query($q, $cb = null) |
|
358
|
|
|
{ |
|
359
|
|
|
if ($this->finished) { |
|
360
|
|
|
throw new ConnectionFinished; |
|
361
|
|
|
} |
|
362
|
|
|
return $this->command(Pool::COM_QUERY, $q, $cb); |
|
363
|
|
|
} |
|
364
|
|
|
|
|
365
|
|
|
/** |
|
366
|
|
|
* Begins a transaction |
|
367
|
|
|
* @param callable $cb Optional. Callback called when response received |
|
|
|
|
|
|
368
|
|
|
* @throws ConnectionFinished |
|
369
|
|
|
*/ |
|
370
|
|
|
public function begin($cb = null) |
|
371
|
|
|
{ |
|
372
|
|
|
$this->query('BEGIN', $cb); |
|
373
|
|
|
$this->acquire(); |
|
374
|
|
|
} |
|
375
|
|
|
|
|
376
|
|
|
/** |
|
377
|
|
|
* Commit a transaction |
|
378
|
|
|
* @param callable $cb Optional. Callback called when response received |
|
|
|
|
|
|
379
|
|
|
* @throws ConnectionFinished |
|
380
|
|
|
*/ |
|
381
|
|
|
public function commit($cb = null) |
|
382
|
|
|
{ |
|
383
|
|
|
$this->query('COMMIT', $cb); |
|
384
|
|
|
$this->release(); |
|
385
|
|
|
} |
|
386
|
|
|
|
|
387
|
|
|
/** |
|
388
|
|
|
* Rollback a transaction |
|
389
|
|
|
* @throws ConnectionFinished |
|
390
|
|
|
*/ |
|
391
|
|
|
public function rollback($cb = null) |
|
392
|
|
|
{ |
|
393
|
|
|
$this->query('ROLLBACK', $cb); |
|
394
|
|
|
$this->release(); |
|
395
|
|
|
} |
|
396
|
|
|
|
|
397
|
|
|
/** |
|
398
|
|
|
* Sends echo-request |
|
399
|
|
|
* @param callable $cb Optional. Callback called when response received |
|
|
|
|
|
|
400
|
|
|
* @callback $cb ( Connection $conn, boolean $success ) |
|
401
|
|
|
* @return boolean Success |
|
402
|
|
|
*/ |
|
403
|
|
|
public function ping($cb = null) |
|
404
|
|
|
{ |
|
405
|
|
|
return $this->command(Pool::COM_PING, '', $cb); |
|
406
|
|
|
} |
|
407
|
|
|
|
|
408
|
|
|
/** |
|
409
|
|
|
* Sends arbitrary command |
|
410
|
|
|
* @param string $cmd Command |
|
411
|
|
|
* @param string $q Data |
|
412
|
|
|
* @param callable $cb Optional |
|
|
|
|
|
|
413
|
|
|
* @throws ConnectionFinished |
|
414
|
|
|
* @callback $cb ( Connection $conn, boolean $success ) |
|
415
|
|
|
* @return boolean Success |
|
416
|
|
|
*/ |
|
417
|
|
View Code Duplication |
public function command($cmd, $q = '', $cb = null) |
|
|
|
|
|
|
418
|
|
|
{ |
|
419
|
|
|
if ($this->phase !== self::PHASE_HANDSHAKED) { |
|
|
|
|
|
|
420
|
|
|
return false; |
|
421
|
|
|
} |
|
422
|
|
|
|
|
423
|
|
|
$this->onResponse->push($cb); |
|
|
|
|
|
|
424
|
|
|
$this->seq = 0; |
|
425
|
|
|
$this->sendPacket(chr($cmd) . $q); |
|
426
|
|
|
|
|
427
|
|
|
return true; |
|
428
|
|
|
} |
|
429
|
|
|
|
|
430
|
|
|
/** |
|
431
|
|
|
* Sets default database name |
|
432
|
|
|
* @param string $name Database name |
|
433
|
|
|
* @return boolean Success |
|
434
|
|
|
*/ |
|
435
|
|
|
public function selectDB($name) |
|
436
|
|
|
{ |
|
437
|
|
|
$this->dbname = $name; |
|
438
|
|
|
|
|
439
|
|
|
if ($this->phase !== self::PHASE_GOT_INIT) { |
|
|
|
|
|
|
440
|
|
|
return $this->query('USE `' . $name . '`'); |
|
441
|
|
|
} |
|
442
|
|
|
|
|
443
|
|
|
return true; |
|
444
|
|
|
} |
|
445
|
|
|
|
|
446
|
|
|
/** |
|
447
|
|
|
* Called when new data received |
|
448
|
|
|
* @return void |
|
449
|
|
|
*/ |
|
450
|
|
|
public function onRead() |
|
451
|
|
|
{ |
|
452
|
|
|
packet: |
|
453
|
|
|
if ($this->state === self::STATE_STANDBY) { |
|
454
|
|
|
if ($this->bev->input->length < 4) { |
|
455
|
|
|
return; |
|
456
|
|
|
} |
|
457
|
|
|
$this->pctSize = Binary::bytes2int($this->read(3), true); |
|
|
|
|
|
|
458
|
|
|
$this->setWatermark($this->pctSize, $this->pctSize); |
|
459
|
|
|
$this->state = self::STATE_BODY; |
|
460
|
|
|
$this->seq = ord($this->read(1)) + 1; |
|
461
|
|
|
} |
|
462
|
|
|
/* STATE_BODY */ |
|
463
|
|
|
$l = $this->bev->input->length; |
|
464
|
|
|
if ($l < $this->pctSize) { |
|
465
|
|
|
return; |
|
466
|
|
|
} |
|
467
|
|
|
$this->state = self::STATE_STANDBY; |
|
468
|
|
|
$this->setWatermark(4); |
|
469
|
|
|
if ($this->phase === 0) { |
|
470
|
|
|
$this->phase = self::PHASE_GOT_INIT; |
|
|
|
|
|
|
471
|
|
|
$this->protover = ord($this->read(1)); |
|
472
|
|
|
if ($this->protover === 0xFF) { // error |
|
473
|
|
|
$fieldCount = $this->protover; |
|
474
|
|
|
$this->protover = 0; |
|
475
|
|
View Code Duplication |
$this->onResponse->push(function ($conn, $result) { |
|
|
|
|
|
|
476
|
|
|
if ($conn->onConnected) { |
|
477
|
|
|
$conn->connected = true; |
|
478
|
|
|
$conn->onConnected->executeAll($conn, $result); |
|
479
|
|
|
$conn->onConnected = null; |
|
480
|
|
|
} |
|
481
|
|
|
}); |
|
482
|
|
|
goto field; |
|
483
|
|
|
} |
|
484
|
|
|
if (($p = $this->search("\x00")) === false) { |
|
485
|
|
|
$this->log('nul-terminator of \'serverver\' is not found'); |
|
486
|
|
|
$this->finish(); |
|
487
|
|
|
return; |
|
488
|
|
|
} |
|
489
|
|
|
$this->serverver = $this->read($p); |
|
|
|
|
|
|
490
|
|
|
$this->drain(1); // drain nul-byte |
|
491
|
|
|
$this->threadId = Binary::bytes2int($this->read(4), true); |
|
|
|
|
|
|
492
|
|
|
$this->scramble = $this->read(8); |
|
|
|
|
|
|
493
|
|
|
$this->drain(1); // ???? |
|
494
|
|
|
|
|
495
|
|
|
$this->serverCaps = Binary::bytes2int($this->read(2), true); |
|
|
|
|
|
|
496
|
|
|
$this->serverLang = ord($this->read(1)); |
|
497
|
|
|
$this->serverStatus = Binary::bytes2int($this->read(2), true); |
|
|
|
|
|
|
498
|
|
|
$this->drain(13); |
|
499
|
|
|
$restScramble = $this->read(12); |
|
500
|
|
|
$this->scramble .= $restScramble; |
|
501
|
|
|
$this->drain(1); |
|
502
|
|
|
|
|
503
|
|
|
$this->auth(); |
|
504
|
|
|
} else { |
|
505
|
|
|
$fieldCount = ord($this->read(1)); |
|
506
|
|
|
field: |
|
507
|
|
|
if ($fieldCount === 0xFF) { |
|
508
|
|
|
// Error packet |
|
509
|
|
|
$u = unpack('v', $this->read(2)); |
|
510
|
|
|
$this->errno = $u[1]; |
|
511
|
|
|
$state = $this->read(6); |
|
|
|
|
|
|
512
|
|
|
$this->errmsg = $this->read($this->pctSize - $l + $this->bev->input->length); |
|
|
|
|
|
|
513
|
|
|
$this->onError(); |
|
514
|
|
|
$this->errno = 0; |
|
515
|
|
|
$this->errmsg = ''; |
|
516
|
|
|
} elseif ($fieldCount === 0x00) { |
|
517
|
|
|
// OK Packet Empty |
|
518
|
|
|
if ($this->phase === self::PHASE_AUTH_SENT) { |
|
519
|
|
|
$this->phase = self::PHASE_HANDSHAKED; |
|
|
|
|
|
|
520
|
|
|
|
|
521
|
|
|
if ($this->dbname !== '') { |
|
522
|
|
|
$this->query('USE `' . $this->dbname . '`'); |
|
523
|
|
|
} |
|
524
|
|
|
} |
|
525
|
|
|
|
|
526
|
|
|
$this->affectedRows = $this->parseEncodedBinary(); |
|
|
|
|
|
|
527
|
|
|
|
|
528
|
|
|
$this->insertId = $this->parseEncodedBinary(); |
|
|
|
|
|
|
529
|
|
|
|
|
530
|
|
|
$u = unpack('v', $this->read(2)); |
|
531
|
|
|
$this->serverStatus = $u[1]; |
|
532
|
|
|
|
|
533
|
|
|
$u = unpack('v', $this->read(2)); |
|
534
|
|
|
$this->warnCount = $u[1]; |
|
535
|
|
|
|
|
536
|
|
|
$this->message = $this->read($this->pctSize - $l + $this->bev->input->length); |
|
|
|
|
|
|
537
|
|
|
$this->onResultDone(); |
|
538
|
|
|
} elseif ($fieldCount === 0xFE) { |
|
539
|
|
|
// EOF Packet |
|
540
|
|
|
if ($this->rsState === self::RS_STATE_ROW) { |
|
541
|
|
|
$this->onResultDone(); |
|
542
|
|
|
} else { |
|
543
|
|
|
++$this->rsState; |
|
544
|
|
|
} |
|
545
|
|
|
} else { |
|
546
|
|
|
// Data packet |
|
547
|
|
|
$this->prependInput(chr($fieldCount)); |
|
548
|
|
|
|
|
549
|
|
|
if ($this->rsState === self::RS_STATE_HEADER) { |
|
550
|
|
|
// Result Set Header Packet |
|
551
|
|
|
$extra = $this->parseEncodedBinary(); |
|
|
|
|
|
|
552
|
|
|
$this->rsState = self::RS_STATE_FIELD; |
|
553
|
|
|
} elseif ($this->rsState === self::RS_STATE_FIELD) { |
|
554
|
|
|
// Field Packet |
|
555
|
|
|
$field = [ |
|
556
|
|
|
'catalog' => $this->parseEncodedString(), |
|
557
|
|
|
'db' => $this->parseEncodedString(), |
|
558
|
|
|
'table' => $this->parseEncodedString(), |
|
559
|
|
|
'org_table' => $this->parseEncodedString(), |
|
560
|
|
|
'name' => $this->parseEncodedString(), |
|
561
|
|
|
'org_name' => $this->parseEncodedString() |
|
562
|
|
|
]; |
|
563
|
|
|
|
|
564
|
|
|
$this->drain(1); // filler |
|
565
|
|
|
|
|
566
|
|
|
$u = unpack('v', $this->read(2)); |
|
567
|
|
|
|
|
568
|
|
|
$field['charset'] = $u[1]; |
|
569
|
|
|
$u = unpack('V', $this->read(4)); |
|
570
|
|
|
$field['length'] = $u[1]; |
|
571
|
|
|
|
|
572
|
|
|
$field['type'] = ord($this->read(1)); |
|
573
|
|
|
|
|
574
|
|
|
$u = unpack('v', $this->read(2)); |
|
575
|
|
|
$field['flags'] = $u[1]; |
|
576
|
|
|
|
|
577
|
|
|
$field['decimals'] = ord($this->read(1)); |
|
578
|
|
|
|
|
579
|
|
|
$this->resultFields[] = $field; |
|
580
|
|
|
} elseif ($this->rsState === self::RS_STATE_ROW) { |
|
581
|
|
|
// Row Packet |
|
582
|
|
|
$row = []; |
|
583
|
|
|
|
|
584
|
|
|
for ($i = 0, $nf = sizeof($this->resultFields); $i < $nf; ++$i) { |
|
585
|
|
|
$row[$this->resultFields[$i]['name']] = $this->parseEncodedString(); |
|
586
|
|
|
} |
|
587
|
|
|
|
|
588
|
|
|
$this->resultRows[] = $row; |
|
589
|
|
|
} |
|
590
|
|
|
} |
|
591
|
|
|
} |
|
592
|
|
|
if ($this->finished) { |
|
593
|
|
|
return; |
|
594
|
|
|
} |
|
595
|
|
|
$this->drain($this->pctSize - $l + $this->bev->input->length); // drain the rest of packet |
|
596
|
|
|
goto packet; |
|
597
|
|
|
} |
|
598
|
|
|
|
|
599
|
|
|
/** |
|
600
|
|
|
* Called when connection finishes |
|
601
|
|
|
* @return void |
|
602
|
|
|
*/ |
|
603
|
|
|
public function onFinish() |
|
604
|
|
|
{ |
|
605
|
|
|
$this->command(Pool::COM_QUIT); |
|
606
|
|
|
parent::onFinish(); |
|
607
|
|
|
} |
|
608
|
|
|
|
|
609
|
|
|
/** |
|
610
|
|
|
* Called when the whole result received |
|
611
|
|
|
* @return void |
|
612
|
|
|
*/ |
|
613
|
|
|
public function onResultDone() |
|
614
|
|
|
{ |
|
615
|
|
|
$this->rsState = self::RS_STATE_HEADER; |
|
616
|
|
|
$this->onResponse->executeOne($this, true); |
|
617
|
|
|
$this->checkFree(); |
|
618
|
|
|
$this->resultRows = []; |
|
619
|
|
|
$this->resultFields = []; |
|
620
|
|
|
} |
|
621
|
|
|
|
|
622
|
|
|
/** |
|
623
|
|
|
* Called when error occured |
|
624
|
|
|
* @return void |
|
625
|
|
|
*/ |
|
626
|
|
|
public function onError() |
|
627
|
|
|
{ |
|
628
|
|
|
$this->rsState = self::RS_STATE_HEADER; |
|
629
|
|
|
$this->onResponse->executeOne($this, false); |
|
630
|
|
|
$this->checkFree(); |
|
631
|
|
|
$this->resultRows = []; |
|
632
|
|
|
$this->resultFields = []; |
|
633
|
|
|
|
|
634
|
|
|
if (($this->phase === self::PHASE_AUTH_SENT) || ($this->phase === self::PHASE_GOT_INIT)) { |
|
|
|
|
|
|
635
|
|
|
// in case of auth error |
|
636
|
|
|
$this->phase = self::PHASE_AUTH_ERR; |
|
|
|
|
|
|
637
|
|
|
$this->finish(); |
|
638
|
|
|
} |
|
639
|
|
|
|
|
640
|
|
|
Daemon::log(__METHOD__ . ' #' . $this->errno . ': ' . $this->errmsg); |
|
641
|
|
|
} |
|
642
|
|
|
} |
|
643
|
|
|
|
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.