1 | <?php |
||
2 | /** |
||
3 | * Plasma Driver MySQL component |
||
4 | * Copyright 2018 PlasmaPHP, All Rights Reserved |
||
5 | * |
||
6 | * Website: https://github.com/PlasmaPHP |
||
7 | * License: https://github.com/PlasmaPHP/driver-mysql/blob/master/LICENSE |
||
8 | */ |
||
9 | |||
10 | namespace Plasma\Drivers\MySQL\Messages; |
||
11 | |||
12 | /** |
||
13 | * Utilities for messages. |
||
14 | * @internal |
||
15 | */ |
||
16 | class MessageUtility { |
||
17 | /** |
||
18 | * Parses a 1 byte / 8 bit integer (0 to 255). |
||
19 | * @return int |
||
20 | */ |
||
21 | 11 | static function readInt1(string &$buffer): int { |
|
22 | 11 | return \ord(static::readBuffer($buffer, 1)); |
|
23 | } |
||
24 | |||
25 | /** |
||
26 | * Parses a 2 byte / 16 bit integer (0 to 64 K / 0xFFFF). |
||
27 | * @return int |
||
28 | */ |
||
29 | static function readInt2(string &$buffer): int { |
||
30 | return \unpack('v', static::readBuffer($buffer, 2))[1]; |
||
31 | } |
||
32 | |||
33 | /** |
||
34 | * Parses a 3 byte / 24 bit integer (0 to 16 M / 0xFFFFFF). |
||
35 | * @return int |
||
36 | */ |
||
37 | 11 | static function readInt3(string &$buffer): int { |
|
38 | 11 | return \unpack('V', static::readBuffer($buffer, 3)."\0")[1]; |
|
39 | } |
||
40 | |||
41 | /** |
||
42 | * Parses a 4 byte / 32 bit integer (0 to 4 G / 0xFFFFFFFF). |
||
43 | * @return int |
||
44 | */ |
||
45 | static function readInt4(string &$buffer): int { |
||
46 | return \unpack('V', static::readBuffer($buffer, 4))[1]; |
||
47 | } |
||
48 | |||
49 | /** |
||
50 | * Parses a 8 byte / 64 bit integer (0 to 2^64-1). |
||
51 | * @return int|string |
||
52 | */ |
||
53 | static function readInt8(string &$buffer) { |
||
54 | $strInt = static::readBuffer($buffer, 8); |
||
55 | |||
56 | if(\PHP_INT_SIZE > 4) { |
||
57 | return \unpack('P', $strInt)[1]; |
||
58 | } |
||
59 | |||
60 | $result = \bcadd('0', \unpack('n', \substr($strInt, 0, 2))); |
||
61 | $result = \bcmul($result, '65536'); |
||
62 | $result = \bcadd($result, \unpack('n', \substr($strInt, 2, 2))); |
||
63 | $result = \bcmul($result, '65536'); |
||
64 | $result = \bcadd($result, \unpack('n', \substr($strInt, 4, 2))); |
||
65 | $result = \bcmul($result, '65536'); |
||
66 | $result = \bcadd($result, \unpack('n', \substr($strInt, 6, 2))); |
||
67 | |||
68 | // 9223372036854775808 is equal to (1 << 63) |
||
69 | if(\bccomp($result, '9223372036854775808') !== -1) { |
||
70 | $result = \bcsub($result, '18446744073709551616'); // $result -= (1 << 64) |
||
71 | } |
||
72 | |||
73 | return $result; |
||
74 | } |
||
75 | |||
76 | /** |
||
77 | * Parses length-encoded binary integer. |
||
78 | * Returns the decoded integer 0 to 2^64 or `null` for special null int. |
||
79 | * @return int|null |
||
80 | */ |
||
81 | static function readIntLength(string &$buffer): ?int { |
||
82 | $f = static::readInt1(); |
||
83 | if($f <= 250) { |
||
84 | return $f; |
||
85 | } |
||
86 | |||
87 | if($f === 251) { |
||
88 | return null; |
||
89 | } |
||
90 | |||
91 | if($f === 252) { |
||
92 | return static::readInt2(); |
||
93 | } |
||
94 | |||
95 | if($f === 253) { |
||
96 | return static::readInt3(); |
||
97 | } |
||
98 | |||
99 | return static::readInt8(); |
||
100 | } |
||
101 | |||
102 | /** |
||
103 | * Parses a length-encoded binary string. If length is null, `null` will be returned. |
||
104 | * @return string|null |
||
105 | */ |
||
106 | static function readStringLength(string &$buffer, ?int $length = null): ?string { |
||
107 | $length = ($length !== null ? $length : static::readIntLength()); |
||
108 | if($length === null) { |
||
109 | return null; |
||
110 | } |
||
111 | |||
112 | return static::readBuffer($buffer, $length); |
||
113 | } |
||
114 | |||
115 | /** |
||
116 | * Reads NULL-terminated C string. |
||
117 | * @return string |
||
118 | * @throws \InvalidArgumentException |
||
119 | */ |
||
120 | static function readStringNull(string &$buffer): string { |
||
121 | $pos = \strpos($buffer, "\0"); |
||
122 | if($pos === false) { |
||
123 | throw new \InvalidArgumentException('Missing NULL character'); |
||
124 | } |
||
125 | |||
126 | $str = static::readBuffer($buffer, $pos); |
||
127 | static::readBuffer(1); // discard NULL byte |
||
0 ignored issues
–
show
|
|||
128 | |||
129 | return $str; |
||
130 | } |
||
131 | |||
132 | /** |
||
133 | * @param int $int |
||
134 | * @return string |
||
135 | */ |
||
136 | static function writeInt1(int $int): string { |
||
137 | return \chr($int); |
||
138 | } |
||
139 | |||
140 | /** |
||
141 | * @param int $int |
||
142 | * @return string |
||
143 | */ |
||
144 | static function writeInt2(int $int): string { |
||
145 | return \pack('v', $int); |
||
146 | } |
||
147 | |||
148 | /** |
||
149 | * @param int $int |
||
150 | * @return string |
||
151 | */ |
||
152 | static function writeInt3(int $int): string { |
||
153 | return \substr(\pack('V', $int), 0, 3); |
||
154 | } |
||
155 | |||
156 | /** |
||
157 | * @param int $int |
||
158 | * @return string |
||
159 | */ |
||
160 | static function writeInt4(int $int): string { |
||
161 | return \pack('V', $int); |
||
162 | } |
||
163 | |||
164 | /** |
||
165 | * @param string|int $int |
||
166 | * @return string |
||
167 | */ |
||
168 | static function writeInt8($int): string { |
||
169 | if(\PHP_INT_SIZE > 4) { |
||
170 | return \pack('P', ((int) $int)); |
||
171 | } |
||
172 | |||
173 | if(\bccomp($int, '0') === -1) { |
||
174 | // 18446744073709551616 is equal to (1 << 64) |
||
175 | $int = \bcadd($int, '18446744073709551616'); |
||
176 | } |
||
177 | |||
178 | return \pack('v', \bcmod(\bcdiv($int, '281474976710656'), '65536')). |
||
179 | \pack('v', \bcmod(\bcdiv($int, '4294967296'), '65536')). |
||
180 | \pack('v', \bcdiv($int, '65536'), '65536'). |
||
181 | \pack('v', \bcmod($int, '65536')); |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * @param float $float |
||
186 | * @return string |
||
187 | */ |
||
188 | static function writeFloat(float $float): string { |
||
189 | return \pack('e', $float); |
||
190 | } |
||
191 | |||
192 | /** |
||
193 | * Builds length-encoded binary string. |
||
194 | * @param string|null $s |
||
195 | * @return string |
||
196 | */ |
||
197 | static function writeStringLength(?string $s): string { |
||
198 | if($s === NULL) { |
||
199 | // \xFB (251) |
||
200 | return "\xFB"; |
||
201 | } |
||
202 | |||
203 | $l = \strlen($s); |
||
204 | if($l <= 250) { |
||
205 | return static::writeInt1($l).$s; |
||
206 | } |
||
207 | |||
208 | if($l <= 0xFFFF) { // max 2^16: \xFC (252) |
||
209 | return "\xFC".static::writeInt2($l).$s; |
||
210 | } |
||
211 | |||
212 | if($l <= 0xFFFFFF) { // max 2^24: \xFD (253) |
||
213 | return "\xFD".static::writeInt3($l).$s; |
||
214 | } |
||
215 | |||
216 | return "\xFE".static::writeInt8($l).$s; // max 2^64: \xFE (254) |
||
217 | } |
||
218 | |||
219 | /** |
||
220 | * Reads a specified length from the buffer and discards the read part. |
||
221 | * @return string |
||
222 | */ |
||
223 | 11 | static function readBuffer(string &$buffer, int $length): string { |
|
224 | 11 | $str = \substr($buffer, 0, $length); |
|
225 | 11 | $buffer = \substr($buffer, ($length + 1)); |
|
226 | |||
227 | 11 | return $str; |
|
228 | } |
||
229 | } |
||
230 |
This check compares calls to functions or methods with their respective definitions. If the call has less arguments than are defined, it raises an issue.
If a function is defined several times with a different number of parameters, the check may pick up the wrong definition and report false positives. One codebase where this has been known to happen is Wordpress. Please note the @ignore annotation hint above.