Skip to content

Commit f3ae090

Browse files
committed
Fixup un/signed mess, add support for decoding SHORT in binary protocol
1 parent d7ccc09 commit f3ae090

File tree

2 files changed

+89
-52
lines changed

2 files changed

+89
-52
lines changed

lib/DataTypes.php

Lines changed: 61 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -113,21 +113,24 @@ public static function decodeBinary($type, $str, &$len = 0) {
113113
case self::MYSQL_TYPE_LONGLONG:
114114
case self::MYSQL_TYPE_LONGLONG | 0x80:
115115
$len = 8;
116-
return $unsigned && ($str[7] & "\x80") ? self::decode_unsigned64($str) : self::decode_int64($str);
116+
return $unsigned ? self::decode_unsigned64($str) : self::decode_int64($str);
117117

118118
case self::MYSQL_TYPE_LONG:
119119
case self::MYSQL_TYPE_LONG | 0x80:
120120
case self::MYSQL_TYPE_INT24:
121121
case self::MYSQL_TYPE_INT24 | 0x80:
122122
$len = 4;
123-
$shift = PHP_INT_MAX >> 31 ? 32 : 0;
124-
return $unsigned && ($str[3] & "\x80") ? self::decode_unsigned32($str) : ((self::decode_int32($str) << $shift) >> $shift);
123+
return $unsigned ? self::decode_unsigned32($str) : self::decode_int32($str);
124+
125+
case self::MYSQL_TYPE_SHORT:
126+
case self::MYSQL_TYPE_SHORT | 0x80:
127+
$len = 2;
128+
return $unsigned ? self::decode_unsigned16($str) : self::decode_int16($str);
125129

126130
case self::MYSQL_TYPE_TINY:
127131
case self::MYSQL_TYPE_TINY | 0x80:
128132
$len = 1;
129-
$shift = PHP_INT_MAX >> 31 ? 56 : 24;
130-
return $unsigned ? ord($str) : ((ord($str) << $shift) >> $shift);
133+
return $unsigned ? \ord($str) : self::decode_int8($str);
131134

132135
case self::MYSQL_TYPE_DOUBLE:
133136
$len = 8;
@@ -143,15 +146,15 @@ public static function decodeBinary($type, $str, &$len = 0) {
143146
$year = $month = $day = $hour = $minute = $second = $microsecond = 0;
144147
switch ($len = ord($str) + 1) {
145148
case 12:
146-
$microsecond = self::decode_int32(substr($str, 8));
149+
$microsecond = self::decode_unsigned32(substr($str, 8));
147150
case 8:
148151
$second = ord($str[7]);
149152
$minute = ord($str[6]);
150153
$hour = ord($str[5]);
151154
case 5:
152155
$day = ord($str[4]);
153156
$month = ord($str[3]);
154-
$year = self::decode_int16(substr($str, 1));
157+
$year = self::decode_unsigned16(substr($str, 1));
155158
case 1:
156159
break;
157160

@@ -164,12 +167,12 @@ public static function decodeBinary($type, $str, &$len = 0) {
164167
$negative = $day = $hour = $minute = $second = $microsecond = 0;
165168
switch ($len = ord($str) + 1) {
166169
case 13:
167-
$microsecond = self::decode_int32(substr($str, 9));
170+
$microsecond = self::decode_unsigned32(substr($str, 9));
168171
case 9:
169172
$second = ord($str[8]);
170173
$minute = ord($str[7]);
171174
$hour = ord($str[6]);
172-
$day = self::decode_int32(substr($str, 2));
175+
$day = self::decode_unsigned32(substr($str, 2));
173176
$negative = ord($str[1]);
174177
case 1:
175178
break;
@@ -193,50 +196,50 @@ public static function decodeNullString($str, &$len = 0) {
193196
}
194197

195198
public static function decodeStringOff($str, &$off) {
196-
$len = self::decodeIntOff($str, $off);
199+
$len = self::decodeUnsignedOff($str, $off);
197200
$off += $len;
198201
return substr($str, $off - $len, $len);
199202
}
200203

201-
public static function decodeIntOff($str, &$off) {
204+
public static function decodeUnsignedOff($str, &$off) {
202205
$int = ord($str[$off]);
203206
if ($int < 0xfb) {
204207
$off += 1;
205208
return $int;
206209
} elseif ($int == 0xfc) {
207210
$off += 3;
208-
return self::decode_int16(substr($str, $off - 2, 2));
211+
return self::decode_unsigned16(substr($str, $off - 2, 2));
209212
} elseif ($int == 0xfd) {
210213
$off += 4;
211-
return self::decode_int24(substr($str, $off - 3, 3));
214+
return self::decode_unsigned24(substr($str, $off - 3, 3));
212215
} elseif ($int == 0xfe) {
213216
$off += 9;
214-
return self::decode_int64(substr($str, $off - 8, 8));
217+
return self::decode_unsigned64(substr($str, $off - 8, 8));
215218
} else {
216219
// If that happens connection is borked...
217220
throw new \RangeException("$int is not in ranges [0x00, 0xfa] or [0xfc, 0xfe]");
218221
}
219222
}
220223

221224
public static function decodeString($str, &$intlen = 0, &$len = 0) {
222-
$len = self::decodeInt($str, $intlen);
225+
$len = self::decodeUnsigned($str, $intlen);
223226
return substr($str, $intlen, $len);
224227
}
225228

226-
public static function decodeInt($str, &$len = 0) {
227-
$int = ord($str);
229+
public static function decodeUnsigned($str, &$len = 0) {
230+
$int = \ord($str);
228231
if ($int < 0xfb) {
229232
$len = 1;
230233
return $int;
231234
} elseif ($int == 0xfc) {
232235
$len = 3;
233-
return self::decode_int16(substr($str, 1));
236+
return self::decode_unsigned16(substr($str, 1, 2));
234237
} elseif ($int == 0xfd) {
235238
$len = 4;
236-
return self::decode_int24(substr($str, 1));
239+
return self::decode_unsigned24(substr($str, 1, 4));
237240
} elseif ($int == 0xfe) {
238241
$len = 9;
239-
return self::decode_int64(substr($str, 1));
242+
return self::decode_unsigned64(substr($str, 1, 8));
240243
} else {
241244
// If that happens connection is borked...
242245
throw new \RangeException("$int is not in ranges [0x00, 0xfa] or [0xfc, 0xfe]");
@@ -252,23 +255,57 @@ public static function decode_intByLen($str, $len) {
252255
}
253256

254257
public static function decode_int8($str) {
255-
return ord($str);
258+
$int = \ord($str);
259+
if ($int < (1 << 7)) {
260+
return $int;
261+
}
262+
$shift = PHP_INT_SIZE * 8 - 8;
263+
return $int << $shift >> $shift;
264+
}
265+
266+
public static function decode_unsigned8($str) {
267+
return \ord($str);
256268
}
257269

258270
public static function decode_int16($str) {
271+
$int = unpack("v", $str)[1];
272+
if ($int < (1 << 15)) {
273+
return $int;
274+
}
275+
$shift = PHP_INT_SIZE * 8 - 16;
276+
return $int << $shift >> $shift;
277+
}
278+
279+
public static function decode_unsigned16($str) {
259280
return unpack("v", $str)[1];
260281
}
261282

262283
public static function decode_int24($str) {
284+
$int = unpack("V", substr($str, 0, 3) . "\x00")[1];
285+
if ($int < (1 << 23)) {
286+
return $int;
287+
}
288+
$shift = PHP_INT_SIZE * 8 - 24;
289+
return $int << $shift >> $shift;
290+
}
291+
292+
public static function decode_unsigned24($str) {
263293
return unpack("V", substr($str, 0, 3) . "\x00")[1];
264294
}
265295

266296
public static function decode_int32($str) {
297+
if (PHP_INT_SIZE > 4) {
298+
$int = unpack("V", $str)[1];
299+
if ($int < (1 << 31)) {
300+
return $int;
301+
}
302+
return $int << 32 >> 32;
303+
}
267304
return unpack("V", $str)[1];
268305
}
269306

270307
public static function decode_unsigned32($str) {
271-
if (PHP_INT_MAX >> 31) {
308+
if (PHP_INT_SIZE > 4) {
272309
return unpack("V", $str)[1];
273310
} else {
274311
$int = unpack("v", $str)[1];
@@ -277,7 +314,7 @@ public static function decode_unsigned32($str) {
277314
}
278315

279316
public static function decode_int64($str) {
280-
if (PHP_INT_MAX >> 31) {
317+
if (PHP_INT_SIZE > 4) {
281318
$int = unpack("V2", $str);
282319
return $int[1] + ($int[2] << 32);
283320
} else {
@@ -287,7 +324,7 @@ public static function decode_int64($str) {
287324
}
288325

289326
public static function decode_unsigned64($str) {
290-
if (PHP_INT_MAX >> 31) {
327+
if (PHP_INT_SIZE > 4) {
291328
$int = unpack("V2", $str);
292329
return $int[1] + $int[2] * (1 << 32);
293330
} else {

lib/Processor.php

Lines changed: 28 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -377,7 +377,7 @@ private function established() {
377377
private function handleError($packet) {
378378
$off = 1;
379379

380-
$this->connInfo->errorCode = DataTypes::decode_int16(substr($packet, $off, 2));
380+
$this->connInfo->errorCode = DataTypes::decode_unsigned16(substr($packet, $off, 2));
381381
$off += 2;
382382

383383
if ($this->capabilities & self::CLIENT_PROTOCOL_41) {
@@ -408,17 +408,17 @@ private function handleError($packet) {
408408
private function parseOk($packet) {
409409
$off = 1;
410410

411-
$this->connInfo->affectedRows = DataTypes::decodeInt(substr($packet, $off), $intlen);
411+
$this->connInfo->affectedRows = DataTypes::decodeUnsigned(substr($packet, $off), $intlen);
412412
$off += $intlen;
413413

414-
$this->connInfo->insertId = DataTypes::decodeInt(substr($packet, $off), $intlen);
414+
$this->connInfo->insertId = DataTypes::decodeUnsigned(substr($packet, $off), $intlen);
415415
$off += $intlen;
416416

417417
if ($this->capabilities & (self::CLIENT_PROTOCOL_41 | self::CLIENT_TRANSACTIONS)) {
418-
$this->connInfo->statusFlags = DataTypes::decode_int16(substr($packet, $off));
418+
$this->connInfo->statusFlags = DataTypes::decode_unsigned16(substr($packet, $off));
419419
$off += 2;
420420

421-
$this->connInfo->warnings = DataTypes::decode_int16(substr($packet, $off));
421+
$this->connInfo->warnings = DataTypes::decode_unsigned16(substr($packet, $off));
422422
$off += 2;
423423
}
424424

@@ -433,7 +433,7 @@ private function parseOk($packet) {
433433
while ($len < $sessionStateLen) {
434434
$data = DataTypes::decodeString(substr($sessionState, $len + 1), $datalen, $intlen);
435435

436-
switch ($type = DataTypes::decode_int8(substr($sessionState, $len))) {
436+
switch ($type = DataTypes::decode_unsigned8(substr($sessionState, $len))) {
437437
case SessionStateTypes::SESSION_TRACK_SYSTEM_VARIABLES:
438438
$var = DataTypes::decodeString($data, $varintlen, $strlen);
439439
$this->connInfo->sessionState[SessionStateTypes::SESSION_TRACK_SYSTEM_VARIABLES][$var] = DataTypes::decodeString(substr($data, $varintlen + $strlen));
@@ -468,9 +468,9 @@ private function handleOk($packet) {
468468
/** @see 14.1.3.3 EOF-Packet */
469469
private function parseEof($packet) {
470470
if ($this->capabilities & self::CLIENT_PROTOCOL_41) {
471-
$this->connInfo->warnings = DataTypes::decode_int16(substr($packet, 1));
471+
$this->connInfo->warnings = DataTypes::decode_unsigned16(substr($packet, 1));
472472

473-
$this->connInfo->statusFlags = DataTypes::decode_int16(substr($packet, 3));
473+
$this->connInfo->statusFlags = DataTypes::decode_unsigned16(substr($packet, 3));
474474
}
475475
}
476476

@@ -492,25 +492,25 @@ private function handleHandshake($packet) {
492492
$this->connInfo->serverVersion = DataTypes::decodeNullString(substr($packet, $off), $len);
493493
$off += $len + 1;
494494

495-
$this->connectionId = DataTypes::decode_int32(substr($packet, $off));
495+
$this->connectionId = DataTypes::decode_unsigned32(substr($packet, $off));
496496
$off += 4;
497497

498498
$this->authPluginData = substr($packet, $off, 8);
499499
$off += 8;
500500

501501
$off += 1; // filler byte
502502

503-
$this->serverCapabilities = DataTypes::decode_int16(substr($packet, $off));
503+
$this->serverCapabilities = DataTypes::decode_unsigned16(substr($packet, $off));
504504
$off += 2;
505505

506506
if (\strlen($packet) > $off) {
507507
$this->connInfo->charset = ord(substr($packet, $off));
508508
$off += 1;
509509

510-
$this->connInfo->statusFlags = DataTypes::decode_int16(substr($packet, $off));
510+
$this->connInfo->statusFlags = DataTypes::decode_unsigned16(substr($packet, $off));
511511
$off += 2;
512512

513-
$this->serverCapabilities += DataTypes::decode_int16(substr($packet, $off)) << 16;
513+
$this->serverCapabilities += DataTypes::decode_unsigned16(substr($packet, $off)) << 16;
514514
$off += 2;
515515

516516
$this->authPluginDataLen = $this->serverCapabilities & self::CLIENT_PLUGIN_AUTH ? ord(substr($packet, $off)) : 0;
@@ -569,7 +569,7 @@ private function handleQuery($packet) {
569569
$this->getDeferred()->succeed(new ResultSet($this->connInfo, $result = new ResultProxy));
570570
/* we need to succeed before assigning vars, so that a when() handler won't have a partial result available */
571571
$this->result = $result;
572-
$result->setColumns(DataTypes::decodeInt($packet));
572+
$result->setColumns(DataTypes::decodeUnsigned($packet));
573573
}
574574

575575
/** @see 14.7.1 Binary Protocol Resultset */
@@ -664,16 +664,16 @@ private function parseColumnDefinition($packet) {
664664
$column["original_table"] = DataTypes::decodeStringOff($packet, $off);
665665
$column["name"] = DataTypes::decodeStringOff($packet, $off);
666666
$column["original_name"] = DataTypes::decodeStringOff($packet, $off);
667-
$fixlen = DataTypes::decodeIntOff($packet, $off);
667+
$fixlen = DataTypes::decodeUnsignedOff($packet, $off);
668668

669669
$len = 0;
670-
$column["charset"] = DataTypes::decode_int16(substr($packet, $off + $len));
670+
$column["charset"] = DataTypes::decode_unsigned16(substr($packet, $off + $len));
671671
$len += 2;
672-
$column["columnlen"] = DataTypes::decode_int32(substr($packet, $off + $len));
672+
$column["columnlen"] = DataTypes::decode_unsigned32(substr($packet, $off + $len));
673673
$len += 4;
674674
$column["type"] = ord($packet[$off + $len]);
675675
$len += 1;
676-
$column["flags"] = DataTypes::decode_int16(substr($packet, $off + $len));
676+
$column["flags"] = DataTypes::decode_unsigned16(substr($packet, $off + $len));
677677
$len += 2;
678678
$column["decimals"] = ord($packet[$off + $len]);
679679
//$len += 1;
@@ -683,21 +683,21 @@ private function parseColumnDefinition($packet) {
683683
$column["table"] = DataTypes::decodeStringOff($packet, $off);
684684
$column["name"] = DataTypes::decodeStringOff($packet, $off);
685685

686-
$collen = DataTypes::decodeIntOff($packet, $off);
686+
$collen = DataTypes::decodeUnsignedOff($packet, $off);
687687
$column["columnlen"] = DataTypes::decode_intByLen(substr($packet, $off), $collen);
688688
$off += $collen;
689689

690-
$typelen = DataTypes::decodeIntOff($packet, $off);
690+
$typelen = DataTypes::decodeUnsignedOff($packet, $off);
691691
$column["type"] = DataTypes::decode_intByLen(substr($packet, $off), $typelen);
692692
$off += $typelen;
693693

694694
$len = 1;
695-
$flaglen = $this->capabilities & self::CLIENT_LONG_FLAG ? DataTypes::decodeInt(substr($packet, $off, 9), $len) : ord($packet[$off]);
695+
$flaglen = $this->capabilities & self::CLIENT_LONG_FLAG ? DataTypes::decodeUnsigned(substr($packet, $off, 9), $len) : ord($packet[$off]);
696696
$off += $len;
697697

698698
if ($flaglen > 2) {
699699
$len = 2;
700-
$column["flags"] = DataTypes::decode_int16(substr($packet, $off, 4));
700+
$column["flags"] = DataTypes::decode_unsigned16(substr($packet, $off, 4));
701701
} else {
702702
$len = 1;
703703
$column["flags"] = ord($packet[$off]);
@@ -801,18 +801,18 @@ private function handlePrepare($packet) {
801801
}
802802
$off = 1;
803803

804-
$stmtId = DataTypes::decode_int32(substr($packet, $off));
804+
$stmtId = DataTypes::decode_unsigned32(substr($packet, $off));
805805
$off += 4;
806806

807-
$columns = DataTypes::decode_int16(substr($packet, $off));
807+
$columns = DataTypes::decode_unsigned16(substr($packet, $off));
808808
$off += 2;
809809

810-
$params = DataTypes::decode_int16(substr($packet, $off));
810+
$params = DataTypes::decode_unsigned16(substr($packet, $off));
811811
$off += 2;
812812

813813
$off += 1; // filler
814814

815-
$this->connInfo->warnings = DataTypes::decode_int16(substr($packet, $off));
815+
$this->connInfo->warnings = DataTypes::decode_unsigned16(substr($packet, $off));
816816

817817
$this->result = new ResultProxy;
818818
$this->result->columnsToFetch = $params;
@@ -987,9 +987,9 @@ private function parseCompression() {
987987
$inflated = "";
988988
}
989989

990-
$size = DataTypes::decode_int24($buf);
990+
$size = DataTypes::decode_unsigned24($buf);
991991
$this->compressionId = ord($buf[3]);
992-
$uncompressed = DataTypes::decode_int24(substr($buf, 4, 3));
992+
$uncompressed = DataTypes::decode_unsigned24(substr($buf, 4, 3));
993993

994994
$buf = substr($buf, 7);
995995

@@ -1027,7 +1027,7 @@ private function parseMysql() {
10271027
$parsed = [];
10281028
}
10291029

1030-
$len = DataTypes::decode_int24($buf);
1030+
$len = DataTypes::decode_unsigned24($buf);
10311031
$this->seqId = ord($buf[3]);
10321032
$buf = substr($buf, 4);
10331033

0 commit comments

Comments
 (0)