This project does not seem to handle request data directly as such no vulnerable execution paths were found.
include
, or for example
via PHP's auto-loading mechanism.
These results are based on our legacy PHP analysis, consider migrating to our new PHP analysis engine instead. Learn more
1 | <?php |
||
2 | namespace evseevnn\Cassandra\Protocol\Response; |
||
3 | |||
4 | use evseevnn\Cassandra\Enum\DataTypeEnum; |
||
5 | |||
6 | /** |
||
7 | * Class DataStream |
||
8 | * @package evseevnn\Cassandra\Protocol\Response |
||
9 | */ |
||
10 | class DataStream { |
||
11 | |||
12 | /** |
||
13 | * @var string |
||
14 | */ |
||
15 | private $data; |
||
16 | |||
17 | /** |
||
18 | * @var int |
||
19 | */ |
||
20 | private $length; |
||
21 | |||
22 | /** |
||
23 | * @param string $binary |
||
24 | */ |
||
25 | public function __construct($binary) { |
||
26 | $this->data = $binary; |
||
27 | $this->length = strlen($binary); |
||
28 | } |
||
29 | |||
30 | |||
31 | /** |
||
32 | * Read data from stream. |
||
33 | * |
||
34 | * @param int $length |
||
35 | * @throws \Exception |
||
36 | * @return string |
||
37 | */ |
||
38 | protected function read($length) { |
||
39 | if ($this->length < $length) { |
||
40 | throw new \Exception('Reading while at end of stream'); |
||
41 | } |
||
42 | $output = substr($this->data, 0, $length); |
||
43 | $this->data = substr($this->data, $length); |
||
44 | $this->length -= $length; |
||
45 | return $output; |
||
46 | } |
||
47 | |||
48 | /** |
||
49 | * Read single character. |
||
50 | * |
||
51 | * @return int |
||
52 | */ |
||
53 | public function readChar() { |
||
54 | return unpack('C', $this->read(1))[1]; |
||
55 | } |
||
56 | |||
57 | /** |
||
58 | * Read unsigned short. |
||
59 | * |
||
60 | * @return int |
||
61 | */ |
||
62 | public function readShort() { |
||
63 | return unpack('n', $this->read(2))[1]; |
||
64 | } |
||
65 | |||
66 | /** |
||
67 | * Read unsigned int. |
||
68 | * |
||
69 | * @param bool $isCollectionElement |
||
70 | * @return int |
||
71 | */ |
||
72 | public function readInt($isCollectionElement = false) { |
||
73 | if ($isCollectionElement) { |
||
74 | $length = $this->readShort(); |
||
75 | return unpack('l', strrev($this->read($length)))[1]; |
||
76 | } |
||
77 | return unpack('l', strrev($this->read(4)))[1]; |
||
78 | } |
||
79 | |||
80 | /** |
||
81 | * Read unsigned big int; |
||
82 | * |
||
83 | * @return int; |
||
0 ignored issues
–
show
|
|||
84 | */ |
||
85 | function readBigInt($isCollectionElement = false) { |
||
0 ignored issues
–
show
|
|||
86 | if ($isCollectionElement) { |
||
87 | $length = $this->readShort(); |
||
88 | } else { |
||
89 | $length = 8; |
||
90 | } |
||
91 | $data = $this->read($length); |
||
92 | $arr = unpack('N2', $data); |
||
93 | |||
94 | if (PHP_INT_SIZE == 4) { |
||
95 | $hi = $arr[1]; |
||
96 | $lo = $arr[2]; |
||
97 | $isNeg = $hi < 0; |
||
98 | |||
99 | // Check for a negative |
||
100 | if ($isNeg) { |
||
101 | $hi = ~$hi & (int)0xffffffff; |
||
102 | $lo = ~$lo & (int)0xffffffff; |
||
103 | |||
104 | if ($lo == (int)0xffffffff) { |
||
105 | $hi++; |
||
106 | $lo = 0; |
||
107 | } else { |
||
108 | $lo++; |
||
109 | } |
||
110 | } |
||
111 | |||
112 | // Force 32bit words in excess of 2G to pe positive - we deal wigh sign |
||
113 | // explicitly below |
||
114 | if ($hi & (int)0x80000000) { |
||
115 | $hi &= (int)0x7fffffff; |
||
116 | $hi += 0x80000000; |
||
117 | } |
||
118 | |||
119 | if ($lo & (int)0x80000000) { |
||
120 | $lo &= (int)0x7fffffff; |
||
121 | $lo += 0x80000000; |
||
122 | } |
||
123 | |||
124 | $value = $hi * 4294967296 + $lo; |
||
125 | |||
126 | if ($isNeg) { |
||
127 | $value = 0 - $value; |
||
128 | } |
||
129 | } else { |
||
130 | if ($arr[2] & 0x80000000) { |
||
131 | $arr[2] = $arr[2] & 0xffffffff; |
||
132 | } |
||
133 | |||
134 | if ($arr[1] & 0x80000000) { |
||
135 | $arr[1] = $arr[1] & 0xffffffff; |
||
136 | $arr[1] = $arr[1] ^ 0xffffffff; |
||
137 | $arr[2] = $arr[2] ^ 0xffffffff; |
||
138 | $value = 0 - $arr[1]*4294967296 - $arr[2] - 1; |
||
139 | } else { |
||
140 | $value = $arr[1]*4294967296 + $arr[2]; |
||
141 | } |
||
142 | } |
||
143 | |||
144 | return $value; |
||
145 | } |
||
146 | |||
147 | /** |
||
148 | * Read string. |
||
149 | * |
||
150 | * @return string |
||
151 | */ |
||
152 | public function readString() { |
||
153 | $length = $this->readShort(); |
||
154 | return $this->read($length); |
||
155 | } |
||
156 | |||
157 | /** |
||
158 | * Read long string. |
||
159 | * |
||
160 | * @return string |
||
161 | */ |
||
162 | public function readLongString() { |
||
163 | $length = $this->readInt(); |
||
164 | return $this->read($length); |
||
165 | } |
||
166 | |||
167 | /** |
||
168 | * Read bytes. |
||
169 | * |
||
170 | * @param bool $isCollectionElement |
||
171 | * @return string |
||
172 | */ |
||
173 | public function readBytes($isCollectionElement = false) { |
||
174 | if ($isCollectionElement) |
||
175 | $this->readShort(); |
||
176 | $length = $this->readInt(); |
||
177 | |||
178 | if ($length == -1) |
||
179 | return null; |
||
180 | |||
181 | return $this->read($length); |
||
182 | } |
||
183 | |||
184 | /** |
||
185 | * Read uuid. |
||
186 | * |
||
187 | * @param bool $isCollectionElement |
||
188 | * @return string |
||
189 | */ |
||
190 | public function readUuid($isCollectionElement = false) { |
||
191 | if ($isCollectionElement) |
||
192 | $this->readShort(); |
||
193 | $uuid = ''; |
||
194 | $data = $this->read(16); |
||
195 | |||
196 | for ($i = 0; $i < 16; ++$i) { |
||
197 | if ($i == 4 || $i == 6 || $i == 8 || $i == 10) { |
||
198 | $uuid .= '-'; |
||
199 | } |
||
200 | $uuid .= str_pad(dechex(ord($data{$i})), 2, '0', STR_PAD_LEFT); |
||
201 | } |
||
202 | |||
203 | return $uuid; |
||
204 | } |
||
205 | |||
206 | /** |
||
207 | * Read timestamp. |
||
208 | * |
||
209 | * Cassandra is using the default java date representation, which is the |
||
210 | * milliseconds since epoch. Since we cannot use 64 bits integers without |
||
211 | * extra libraries, we are reading this as two 32 bits numbers and calculate |
||
212 | * the seconds since epoch. |
||
213 | * |
||
214 | * @return int |
||
215 | */ |
||
216 | public function readTimestamp() { |
||
217 | return $this->readBigInt() / 1000; |
||
218 | } |
||
219 | |||
220 | /** |
||
221 | * Read list. |
||
222 | * |
||
223 | * @param $valueType |
||
224 | * @return array |
||
225 | */ |
||
226 | View Code Duplication | public function readList($valueType) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
227 | $list = array(); |
||
228 | $count = $this->readShort(); |
||
229 | for ($i = 0; $i < $count; ++$i) { |
||
230 | $list[] = $this->readByType($valueType, true); |
||
231 | } |
||
232 | return $list; |
||
233 | } |
||
234 | |||
235 | /** |
||
236 | * Read map. |
||
237 | * |
||
238 | * @param $keyType |
||
239 | * @param $valueType |
||
240 | * @return array |
||
241 | */ |
||
242 | View Code Duplication | public function readMap($keyType, $valueType) { |
|
0 ignored issues
–
show
This method seems to be duplicated in your project.
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. ![]() |
|||
243 | $map = array(); |
||
244 | $count = $this->readShort(); |
||
245 | for ($i = 0; $i < $count; ++$i) { |
||
246 | $map[$this->readByType($keyType, true)] = $this->readByType($valueType, true); |
||
247 | } |
||
248 | return $map; |
||
249 | } |
||
250 | |||
251 | /** |
||
252 | * Read float. |
||
253 | * |
||
254 | * @param bool $isCollectionElement |
||
255 | * @return float |
||
256 | */ |
||
257 | public function readFloat($isCollectionElement = false) { |
||
258 | if ($isCollectionElement) { |
||
259 | $this->readShort(); |
||
260 | } |
||
261 | return unpack('f', strrev($this->read(4)))[1]; |
||
262 | } |
||
263 | |||
264 | /** |
||
265 | * Read double. |
||
266 | * |
||
267 | * @param bool $isCollectionElement |
||
268 | * @return double |
||
269 | */ |
||
270 | public function readDouble($isCollectionElement = false) { |
||
271 | if ($isCollectionElement) { |
||
272 | $this->readShort(); |
||
273 | } |
||
274 | return unpack('d', strrev($this->read(8)))[1]; |
||
275 | } |
||
276 | |||
277 | /** |
||
278 | * Read boolean. |
||
279 | * |
||
280 | * @return bool |
||
281 | */ |
||
282 | public function readBoolean() { |
||
283 | return (bool)$this->readChar(); |
||
284 | } |
||
285 | |||
286 | /** |
||
287 | * Read inet. |
||
288 | * |
||
289 | * @param bool $isCollectionElement |
||
290 | * @return string |
||
291 | */ |
||
292 | public function readInet($isCollectionElement = false) { |
||
293 | if ($isCollectionElement) { |
||
294 | $data = $this->read($this->readShort()); |
||
295 | } else { |
||
296 | $data = $this->data; |
||
297 | } |
||
298 | return inet_ntop($data); |
||
299 | } |
||
300 | |||
301 | /** |
||
302 | * Read variable length integer. |
||
303 | * |
||
304 | * @param bool $isCollectionElement |
||
305 | * @return string |
||
306 | */ |
||
307 | public function readVarint($isCollectionElement = false) { |
||
308 | if($isCollectionElement) { |
||
309 | $length = $this->readShort(); |
||
310 | } else { |
||
311 | $length = strlen($this->data); |
||
312 | } |
||
313 | |||
314 | $hex = unpack('H*', $this->read($length)); |
||
315 | return $this->bchexdec($hex[1]); |
||
316 | } |
||
317 | |||
318 | /** |
||
319 | * Read variable length decimal. |
||
320 | * |
||
321 | * @param bool $isCollectionElement |
||
322 | * @return string |
||
323 | */ |
||
324 | public function readDecimal($isCollectionElement = false) { |
||
325 | if ($isCollectionElement) { |
||
326 | $this->readShort(); |
||
327 | } |
||
328 | $scale = $this->readInt(); |
||
329 | $value = $this->readVarint($isCollectionElement); |
||
330 | $len = strlen($value); |
||
331 | return substr($value, 0, $len - $scale) . '.' . substr($value, $len - $scale); |
||
332 | } |
||
333 | |||
334 | /** |
||
335 | * @param array $type |
||
336 | * @param bool $isCollectionElement for collection element used other alg. a temporary solution |
||
337 | * @return mixed |
||
338 | */ |
||
339 | public function readByType(array $type, $isCollectionElement = false) { |
||
340 | |||
341 | if ( $this->data === null ) { |
||
342 | return null; |
||
343 | } |
||
344 | |||
345 | switch ($type['type']) { |
||
346 | case DataTypeEnum::ASCII: |
||
347 | case DataTypeEnum::VARCHAR: |
||
348 | case DataTypeEnum::TEXT: |
||
349 | return $isCollectionElement ? $this->readString() : $this->data; |
||
350 | case DataTypeEnum::BIGINT: |
||
351 | case DataTypeEnum::COUNTER: |
||
352 | return $this->readBigInt($isCollectionElement); |
||
353 | case DataTypeEnum::VARINT: |
||
354 | return $this->readVarint($isCollectionElement); |
||
355 | case DataTypeEnum::CUSTOM: |
||
356 | case DataTypeEnum::BLOB: |
||
357 | return $this->readBytes($isCollectionElement); |
||
358 | case DataTypeEnum::BOOLEAN: |
||
359 | return $this->readBoolean(); |
||
360 | case DataTypeEnum::DECIMAL: |
||
361 | return $this->readDecimal($isCollectionElement); |
||
362 | case DataTypeEnum::DOUBLE: |
||
363 | return $this->readDouble($isCollectionElement); |
||
364 | case DataTypeEnum::FLOAT: |
||
365 | return $this->readFloat($isCollectionElement); |
||
366 | case DataTypeEnum::INT: |
||
367 | return $this->readInt($isCollectionElement); |
||
368 | case DataTypeEnum::TIMESTAMP: |
||
369 | return $this->readTimestamp(); |
||
370 | case DataTypeEnum::UUID: |
||
371 | return $this->readUuid($isCollectionElement); |
||
372 | case DataTypeEnum::TIMEUUID: |
||
373 | return $this->readUuid($isCollectionElement); |
||
374 | case DataTypeEnum::INET: |
||
375 | return $this->readInet($isCollectionElement); |
||
376 | case DataTypeEnum::COLLECTION_LIST: |
||
377 | case DataTypeEnum::COLLECTION_SET: |
||
378 | return $this->readList($type['value']); |
||
379 | case DataTypeEnum::COLLECTION_MAP: |
||
380 | return $this->readMap($type['key'], $type['value']); |
||
381 | } |
||
382 | |||
383 | trigger_error('Unknown type ' . var_export($type, true)); |
||
384 | return null; |
||
385 | } |
||
386 | |||
387 | /** |
||
388 | * |
||
389 | * @param string $hex |
||
390 | * @return string |
||
391 | */ |
||
392 | private function bchexdec($hex) { |
||
393 | if (strlen($hex) == 1) |
||
394 | return hexdec($hex); |
||
395 | |||
396 | $remain = substr($hex, 0, -1); |
||
397 | $last = substr($hex, -1); |
||
398 | return bcadd(bcmul(16, $this->bchexdec($remain)), hexdec($last)); |
||
399 | } |
||
400 | |||
401 | } |
||
402 |
This check marks PHPDoc comments that could not be parsed by our parser. To see which comment annotations we can parse, please refer to our documentation on supported doc-types.