diff --git a/lib/DataTypes.php b/lib/DataTypes.php index 0b99706..6ac6e74 100644 --- a/lib/DataTypes.php +++ b/lib/DataTypes.php @@ -113,21 +113,24 @@ public static function decodeBinary($type, $str, &$len = 0) { case self::MYSQL_TYPE_LONGLONG: case self::MYSQL_TYPE_LONGLONG | 0x80: $len = 8; - return $unsigned && ($str[7] & "\x80") ? self::decode_unsigned64($str) : self::decode_int64($str); + return $unsigned ? self::decode_unsigned64($str) : self::decode_int64($str); case self::MYSQL_TYPE_LONG: case self::MYSQL_TYPE_LONG | 0x80: case self::MYSQL_TYPE_INT24: case self::MYSQL_TYPE_INT24 | 0x80: $len = 4; - $shift = PHP_INT_MAX >> 31 ? 32 : 0; - return $unsigned && ($str[3] & "\x80") ? self::decode_unsigned32($str) : ((self::decode_int32($str) << $shift) >> $shift); + return $unsigned ? self::decode_unsigned32($str) : self::decode_int32($str); + + case self::MYSQL_TYPE_SHORT: + case self::MYSQL_TYPE_SHORT | 0x80: + $len = 2; + return $unsigned ? self::decode_unsigned16($str) : self::decode_int16($str); case self::MYSQL_TYPE_TINY: case self::MYSQL_TYPE_TINY | 0x80: $len = 1; - $shift = PHP_INT_MAX >> 31 ? 56 : 24; - return $unsigned ? ord($str) : ((ord($str) << $shift) >> $shift); + return $unsigned ? \ord($str) : self::decode_int8($str); case self::MYSQL_TYPE_DOUBLE: $len = 8; @@ -143,7 +146,7 @@ public static function decodeBinary($type, $str, &$len = 0) { $year = $month = $day = $hour = $minute = $second = $microsecond = 0; switch ($len = ord($str) + 1) { case 12: - $microsecond = self::decode_int32(substr($str, 8)); + $microsecond = self::decode_unsigned32(substr($str, 8)); case 8: $second = ord($str[7]); $minute = ord($str[6]); @@ -151,7 +154,7 @@ public static function decodeBinary($type, $str, &$len = 0) { case 5: $day = ord($str[4]); $month = ord($str[3]); - $year = self::decode_int16(substr($str, 1)); + $year = self::decode_unsigned16(substr($str, 1)); case 1: break; @@ -164,12 +167,12 @@ public static function decodeBinary($type, $str, &$len = 0) { $negative = $day = $hour = $minute = $second = $microsecond = 0; switch ($len = ord($str) + 1) { case 13: - $microsecond = self::decode_int32(substr($str, 9)); + $microsecond = self::decode_unsigned32(substr($str, 9)); case 9: $second = ord($str[8]); $minute = ord($str[7]); $hour = ord($str[6]); - $day = self::decode_int32(substr($str, 2)); + $day = self::decode_unsigned32(substr($str, 2)); $negative = ord($str[1]); case 1: break; @@ -193,25 +196,25 @@ public static function decodeNullString($str, &$len = 0) { } public static function decodeStringOff($str, &$off) { - $len = self::decodeIntOff($str, $off); + $len = self::decodeUnsignedOff($str, $off); $off += $len; return substr($str, $off - $len, $len); } - public static function decodeIntOff($str, &$off) { + public static function decodeUnsignedOff($str, &$off) { $int = ord($str[$off]); if ($int < 0xfb) { $off += 1; return $int; } elseif ($int == 0xfc) { $off += 3; - return self::decode_int16(substr($str, $off - 2, 2)); + return self::decode_unsigned16(substr($str, $off - 2, 2)); } elseif ($int == 0xfd) { $off += 4; - return self::decode_int24(substr($str, $off - 3, 3)); + return self::decode_unsigned24(substr($str, $off - 3, 3)); } elseif ($int == 0xfe) { $off += 9; - return self::decode_int64(substr($str, $off - 8, 8)); + return self::decode_unsigned64(substr($str, $off - 8, 8)); } else { // If that happens connection is borked... throw new \RangeException("$int is not in ranges [0x00, 0xfa] or [0xfc, 0xfe]"); @@ -219,24 +222,24 @@ public static function decodeIntOff($str, &$off) { } public static function decodeString($str, &$intlen = 0, &$len = 0) { - $len = self::decodeInt($str, $intlen); + $len = self::decodeUnsigned($str, $intlen); return substr($str, $intlen, $len); } - public static function decodeInt($str, &$len = 0) { - $int = ord($str); + public static function decodeUnsigned($str, &$len = 0) { + $int = \ord($str); if ($int < 0xfb) { $len = 1; return $int; } elseif ($int == 0xfc) { $len = 3; - return self::decode_int16(substr($str, 1)); + return self::decode_unsigned16(substr($str, 1, 2)); } elseif ($int == 0xfd) { $len = 4; - return self::decode_int24(substr($str, 1)); + return self::decode_unsigned24(substr($str, 1, 4)); } elseif ($int == 0xfe) { $len = 9; - return self::decode_int64(substr($str, 1)); + return self::decode_unsigned64(substr($str, 1, 8)); } else { // If that happens connection is borked... throw new \RangeException("$int is not in ranges [0x00, 0xfa] or [0xfc, 0xfe]"); @@ -252,23 +255,57 @@ public static function decode_intByLen($str, $len) { } public static function decode_int8($str) { - return ord($str); + $int = \ord($str); + if ($int < (1 << 7)) { + return $int; + } + $shift = PHP_INT_SIZE * 8 - 8; + return $int << $shift >> $shift; + } + + public static function decode_unsigned8($str) { + return \ord($str); } public static function decode_int16($str) { + $int = unpack("v", $str)[1]; + if ($int < (1 << 15)) { + return $int; + } + $shift = PHP_INT_SIZE * 8 - 16; + return $int << $shift >> $shift; + } + + public static function decode_unsigned16($str) { return unpack("v", $str)[1]; } public static function decode_int24($str) { + $int = unpack("V", substr($str, 0, 3) . "\x00")[1]; + if ($int < (1 << 23)) { + return $int; + } + $shift = PHP_INT_SIZE * 8 - 24; + return $int << $shift >> $shift; + } + + public static function decode_unsigned24($str) { return unpack("V", substr($str, 0, 3) . "\x00")[1]; } public static function decode_int32($str) { + if (PHP_INT_SIZE > 4) { + $int = unpack("V", $str)[1]; + if ($int < (1 << 31)) { + return $int; + } + return $int << 32 >> 32; + } return unpack("V", $str)[1]; } public static function decode_unsigned32($str) { - if (PHP_INT_MAX >> 31) { + if (PHP_INT_SIZE > 4) { return unpack("V", $str)[1]; } else { $int = unpack("v", $str)[1]; @@ -277,7 +314,7 @@ public static function decode_unsigned32($str) { } public static function decode_int64($str) { - if (PHP_INT_MAX >> 31) { + if (PHP_INT_SIZE > 4) { $int = unpack("V2", $str); return $int[1] + ($int[2] << 32); } else { @@ -287,7 +324,7 @@ public static function decode_int64($str) { } public static function decode_unsigned64($str) { - if (PHP_INT_MAX >> 31) { + if (PHP_INT_SIZE > 4) { $int = unpack("V2", $str); return $int[1] + $int[2] * (1 << 32); } else { diff --git a/lib/Processor.php b/lib/Processor.php index 97ccab8..6c1720d 100644 --- a/lib/Processor.php +++ b/lib/Processor.php @@ -377,7 +377,7 @@ private function established() { private function handleError($packet) { $off = 1; - $this->connInfo->errorCode = DataTypes::decode_int16(substr($packet, $off, 2)); + $this->connInfo->errorCode = DataTypes::decode_unsigned16(substr($packet, $off, 2)); $off += 2; if ($this->capabilities & self::CLIENT_PROTOCOL_41) { @@ -408,17 +408,17 @@ private function handleError($packet) { private function parseOk($packet) { $off = 1; - $this->connInfo->affectedRows = DataTypes::decodeInt(substr($packet, $off), $intlen); + $this->connInfo->affectedRows = DataTypes::decodeUnsigned(substr($packet, $off), $intlen); $off += $intlen; - $this->connInfo->insertId = DataTypes::decodeInt(substr($packet, $off), $intlen); + $this->connInfo->insertId = DataTypes::decodeUnsigned(substr($packet, $off), $intlen); $off += $intlen; if ($this->capabilities & (self::CLIENT_PROTOCOL_41 | self::CLIENT_TRANSACTIONS)) { - $this->connInfo->statusFlags = DataTypes::decode_int16(substr($packet, $off)); + $this->connInfo->statusFlags = DataTypes::decode_unsigned16(substr($packet, $off)); $off += 2; - $this->connInfo->warnings = DataTypes::decode_int16(substr($packet, $off)); + $this->connInfo->warnings = DataTypes::decode_unsigned16(substr($packet, $off)); $off += 2; } @@ -433,7 +433,7 @@ private function parseOk($packet) { while ($len < $sessionStateLen) { $data = DataTypes::decodeString(substr($sessionState, $len + 1), $datalen, $intlen); - switch ($type = DataTypes::decode_int8(substr($sessionState, $len))) { + switch ($type = DataTypes::decode_unsigned8(substr($sessionState, $len))) { case SessionStateTypes::SESSION_TRACK_SYSTEM_VARIABLES: $var = DataTypes::decodeString($data, $varintlen, $strlen); $this->connInfo->sessionState[SessionStateTypes::SESSION_TRACK_SYSTEM_VARIABLES][$var] = DataTypes::decodeString(substr($data, $varintlen + $strlen)); @@ -468,9 +468,9 @@ private function handleOk($packet) { /** @see 14.1.3.3 EOF-Packet */ private function parseEof($packet) { if ($this->capabilities & self::CLIENT_PROTOCOL_41) { - $this->connInfo->warnings = DataTypes::decode_int16(substr($packet, 1)); + $this->connInfo->warnings = DataTypes::decode_unsigned16(substr($packet, 1)); - $this->connInfo->statusFlags = DataTypes::decode_int16(substr($packet, 3)); + $this->connInfo->statusFlags = DataTypes::decode_unsigned16(substr($packet, 3)); } } @@ -492,7 +492,7 @@ private function handleHandshake($packet) { $this->connInfo->serverVersion = DataTypes::decodeNullString(substr($packet, $off), $len); $off += $len + 1; - $this->connectionId = DataTypes::decode_int32(substr($packet, $off)); + $this->connectionId = DataTypes::decode_unsigned32(substr($packet, $off)); $off += 4; $this->authPluginData = substr($packet, $off, 8); @@ -500,17 +500,17 @@ private function handleHandshake($packet) { $off += 1; // filler byte - $this->serverCapabilities = DataTypes::decode_int16(substr($packet, $off)); + $this->serverCapabilities = DataTypes::decode_unsigned16(substr($packet, $off)); $off += 2; if (\strlen($packet) > $off) { $this->connInfo->charset = ord(substr($packet, $off)); $off += 1; - $this->connInfo->statusFlags = DataTypes::decode_int16(substr($packet, $off)); + $this->connInfo->statusFlags = DataTypes::decode_unsigned16(substr($packet, $off)); $off += 2; - $this->serverCapabilities += DataTypes::decode_int16(substr($packet, $off)) << 16; + $this->serverCapabilities += DataTypes::decode_unsigned16(substr($packet, $off)) << 16; $off += 2; $this->authPluginDataLen = $this->serverCapabilities & self::CLIENT_PLUGIN_AUTH ? ord(substr($packet, $off)) : 0; @@ -569,7 +569,7 @@ private function handleQuery($packet) { $this->getDeferred()->succeed(new ResultSet($this->connInfo, $result = new ResultProxy)); /* we need to succeed before assigning vars, so that a when() handler won't have a partial result available */ $this->result = $result; - $result->setColumns(DataTypes::decodeInt($packet)); + $result->setColumns(DataTypes::decodeUnsigned($packet)); } /** @see 14.7.1 Binary Protocol Resultset */ @@ -664,16 +664,16 @@ private function parseColumnDefinition($packet) { $column["original_table"] = DataTypes::decodeStringOff($packet, $off); $column["name"] = DataTypes::decodeStringOff($packet, $off); $column["original_name"] = DataTypes::decodeStringOff($packet, $off); - $fixlen = DataTypes::decodeIntOff($packet, $off); + $fixlen = DataTypes::decodeUnsignedOff($packet, $off); $len = 0; - $column["charset"] = DataTypes::decode_int16(substr($packet, $off + $len)); + $column["charset"] = DataTypes::decode_unsigned16(substr($packet, $off + $len)); $len += 2; - $column["columnlen"] = DataTypes::decode_int32(substr($packet, $off + $len)); + $column["columnlen"] = DataTypes::decode_unsigned32(substr($packet, $off + $len)); $len += 4; $column["type"] = ord($packet[$off + $len]); $len += 1; - $column["flags"] = DataTypes::decode_int16(substr($packet, $off + $len)); + $column["flags"] = DataTypes::decode_unsigned16(substr($packet, $off + $len)); $len += 2; $column["decimals"] = ord($packet[$off + $len]); //$len += 1; @@ -683,21 +683,21 @@ private function parseColumnDefinition($packet) { $column["table"] = DataTypes::decodeStringOff($packet, $off); $column["name"] = DataTypes::decodeStringOff($packet, $off); - $collen = DataTypes::decodeIntOff($packet, $off); + $collen = DataTypes::decodeUnsignedOff($packet, $off); $column["columnlen"] = DataTypes::decode_intByLen(substr($packet, $off), $collen); $off += $collen; - $typelen = DataTypes::decodeIntOff($packet, $off); + $typelen = DataTypes::decodeUnsignedOff($packet, $off); $column["type"] = DataTypes::decode_intByLen(substr($packet, $off), $typelen); $off += $typelen; $len = 1; - $flaglen = $this->capabilities & self::CLIENT_LONG_FLAG ? DataTypes::decodeInt(substr($packet, $off, 9), $len) : ord($packet[$off]); + $flaglen = $this->capabilities & self::CLIENT_LONG_FLAG ? DataTypes::decodeUnsigned(substr($packet, $off, 9), $len) : ord($packet[$off]); $off += $len; if ($flaglen > 2) { $len = 2; - $column["flags"] = DataTypes::decode_int16(substr($packet, $off, 4)); + $column["flags"] = DataTypes::decode_unsigned16(substr($packet, $off, 4)); } else { $len = 1; $column["flags"] = ord($packet[$off]); @@ -801,18 +801,18 @@ private function handlePrepare($packet) { } $off = 1; - $stmtId = DataTypes::decode_int32(substr($packet, $off)); + $stmtId = DataTypes::decode_unsigned32(substr($packet, $off)); $off += 4; - $columns = DataTypes::decode_int16(substr($packet, $off)); + $columns = DataTypes::decode_unsigned16(substr($packet, $off)); $off += 2; - $params = DataTypes::decode_int16(substr($packet, $off)); + $params = DataTypes::decode_unsigned16(substr($packet, $off)); $off += 2; $off += 1; // filler - $this->connInfo->warnings = DataTypes::decode_int16(substr($packet, $off)); + $this->connInfo->warnings = DataTypes::decode_unsigned16(substr($packet, $off)); $this->result = new ResultProxy; $this->result->columnsToFetch = $params; @@ -987,9 +987,9 @@ private function parseCompression() { $inflated = ""; } - $size = DataTypes::decode_int24($buf); + $size = DataTypes::decode_unsigned24($buf); $this->compressionId = ord($buf[3]); - $uncompressed = DataTypes::decode_int24(substr($buf, 4, 3)); + $uncompressed = DataTypes::decode_unsigned24(substr($buf, 4, 3)); $buf = substr($buf, 7); @@ -1027,7 +1027,7 @@ private function parseMysql() { $parsed = []; } - $len = DataTypes::decode_int24($buf); + $len = DataTypes::decode_unsigned24($buf); $this->seqId = ord($buf[3]); $buf = substr($buf, 4);