Skip to content

Commit fce4ce6

Browse files
committed
Always convert overflowed int keys to string, add psalm
1 parent 3a0a866 commit fce4ce6

17 files changed

Lines changed: 290 additions & 47 deletions

.gitattributes

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,3 +6,4 @@ tests export-ignore
66
.php_cs.dist export-ignore
77
dockerfile.sh export-ignore
88
phpunit.xml.dist export-ignore
9+
psalm.xml export-ignore

.github/workflows/qa.yml

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,7 +38,9 @@ jobs:
3838
- name: Check code quality
3939
env: ${{ matrix.env }}
4040
if: ${{ env.QA }}
41-
run: docker run --rm -v $PWD:/msgpack -w /msgpack msgpack php vendor/bin/php-cs-fixer fix --dry-run --diff --verbose .
41+
run: |
42+
docker run --rm -v $PWD:/msgpack -w /msgpack msgpack php vendor/bin/php-cs-fixer fix --dry-run --diff --verbose .
43+
docker run --rm -v $PWD:/msgpack -w /msgpack msgpack php vendor/bin/psalm
4244
4345
- name: Upload code coverage to Scrutinizer
4446
env: ${{ matrix.env }}

composer.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@
1616
"require-dev": {
1717
"ext-gmp": "*",
1818
"friendsofphp/php-cs-fixer": "^2.14",
19-
"phpunit/phpunit": "^7.1|^8|^9"
19+
"phpunit/phpunit": "^7.1|^8|^9",
20+
"vimeo/psalm": "^3.9|^4"
2021
},
2122
"suggest": {
2223
"ext-decimal": "For converting overflowed integers to Decimal objects",

psalm.xml

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
<?xml version="1.0"?>
2+
<psalm
3+
errorLevel="2"
4+
resolveFromConfigFile="true"
5+
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
6+
xmlns="https://getpsalm.org/schema/config"
7+
xsi:schemaLocation="https://getpsalm.org/schema/config vendor/vimeo/psalm/config.xsd"
8+
>
9+
<projectFiles>
10+
<directory name="src" />
11+
<ignoreFiles>
12+
<directory name="vendor" />
13+
</ignoreFiles>
14+
</projectFiles>
15+
</psalm>

src/BufferUnpacker.php

Lines changed: 111 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -20,14 +20,19 @@
2020

2121
class BufferUnpacker
2222
{
23+
/** @var string */
2324
private $buffer;
25+
26+
/** @var int */
2427
private $offset = 0;
28+
29+
/** @var bool */
2530
private $isBigIntAsDec;
31+
32+
/** @var bool */
2633
private $isBigIntAsGmp;
2734

28-
/**
29-
* @var Extension[]
30-
*/
35+
/** @var Extension[] */
3136
private $extensions = [];
3237

3338
/**
@@ -109,6 +114,9 @@ public function seek(int $offset) : self
109114
return $this;
110115
}
111116

117+
/**
118+
* @param positive-int $length
119+
*/
112120
public function skip(int $length) : self
113121
{
114122
$offset = $this->offset + $length;
@@ -179,6 +187,9 @@ public function tryUnpack() : array
179187
return $data;
180188
}
181189

190+
/**
191+
* @return mixed
192+
*/
182193
public function unpack()
183194
{
184195
if (!isset($this->buffer[$this->offset])) {
@@ -280,6 +291,9 @@ public function unpack()
280291
throw UnpackingFailedException::unknownCode($c);
281292
}
282293

294+
/**
295+
* @return null
296+
*/
283297
public function unpackNil()
284298
{
285299
if (!isset($this->buffer[$this->offset])) {
@@ -295,6 +309,9 @@ public function unpackNil()
295309
throw UnpackingFailedException::unexpectedCode(\ord($this->buffer[$this->offset++]), 'nil');
296310
}
297311

312+
/**
313+
* @return bool
314+
*/
298315
public function unpackBool()
299316
{
300317
if (!isset($this->buffer[$this->offset])) {
@@ -314,6 +331,9 @@ public function unpackBool()
314331
throw UnpackingFailedException::unexpectedCode($c, 'bool');
315332
}
316333

334+
/**
335+
* @return Decimal|\GMP|int|string
336+
*/
317337
public function unpackInt()
318338
{
319339
if (!isset($this->buffer[$this->offset])) {
@@ -348,6 +368,9 @@ public function unpackInt()
348368
throw UnpackingFailedException::unexpectedCode($c, 'int');
349369
}
350370

371+
/**
372+
* @return float
373+
*/
351374
public function unpackFloat()
352375
{
353376
if (!isset($this->buffer[$this->offset])) {
@@ -367,6 +390,9 @@ public function unpackFloat()
367390
throw UnpackingFailedException::unexpectedCode($c, 'float');
368391
}
369392

393+
/**
394+
* @return string
395+
*/
370396
public function unpackStr()
371397
{
372398
if (!isset($this->buffer[$this->offset])) {
@@ -392,6 +418,9 @@ public function unpackStr()
392418
throw UnpackingFailedException::unexpectedCode($c, 'str');
393419
}
394420

421+
/**
422+
* @return string
423+
*/
395424
public function unpackBin()
396425
{
397426
if (!isset($this->buffer[$this->offset])) {
@@ -414,6 +443,9 @@ public function unpackBin()
414443
throw UnpackingFailedException::unexpectedCode($c, 'bin');
415444
}
416445

446+
/**
447+
* @return array
448+
*/
417449
public function unpackArray()
418450
{
419451
$size = $this->unpackArrayHeader();
@@ -426,6 +458,9 @@ public function unpackArray()
426458
return $array;
427459
}
428460

461+
/**
462+
* @return int
463+
*/
429464
public function unpackArrayHeader()
430465
{
431466
if (!isset($this->buffer[$this->offset])) {
@@ -448,6 +483,9 @@ public function unpackArrayHeader()
448483
throw UnpackingFailedException::unexpectedCode($c, 'array');
449484
}
450485

486+
/**
487+
* @return array
488+
*/
451489
public function unpackMap()
452490
{
453491
$size = $this->unpackMapHeader();
@@ -460,6 +498,9 @@ public function unpackMap()
460498
return $map;
461499
}
462500

501+
/**
502+
* @return int
503+
*/
463504
public function unpackMapHeader()
464505
{
465506
if (!isset($this->buffer[$this->offset])) {
@@ -482,6 +523,9 @@ public function unpackMapHeader()
482523
throw UnpackingFailedException::unexpectedCode($c, 'map');
483524
}
484525

526+
/**
527+
* @return mixed
528+
*/
485529
public function unpackExt()
486530
{
487531
if (!isset($this->buffer[$this->offset])) {
@@ -505,6 +549,9 @@ public function unpackExt()
505549
throw UnpackingFailedException::unexpectedCode($c, 'ext');
506550
}
507551

552+
/**
553+
* @return int
554+
*/
508555
private function unpackUint8()
509556
{
510557
if (!isset($this->buffer[$this->offset])) {
@@ -514,6 +561,9 @@ private function unpackUint8()
514561
return \ord($this->buffer[$this->offset++]);
515562
}
516563

564+
/**
565+
* @return int
566+
*/
517567
private function unpackUint16()
518568
{
519569
if (!isset($this->buffer[$this->offset + 1])) {
@@ -524,6 +574,9 @@ private function unpackUint16()
524574
| \ord($this->buffer[$this->offset++]);
525575
}
526576

577+
/**
578+
* @return int
579+
*/
527580
private function unpackUint32()
528581
{
529582
if (!isset($this->buffer[$this->offset + 3])) {
@@ -536,6 +589,9 @@ private function unpackUint32()
536589
| \ord($this->buffer[$this->offset++]);
537590
}
538591

592+
/**
593+
* @return Decimal|\GMP|int|string
594+
*/
539595
private function unpackUint64()
540596
{
541597
if (!isset($this->buffer[$this->offset + 7])) {
@@ -558,6 +614,24 @@ private function unpackUint64()
558614
return \sprintf('%u', $num);
559615
}
560616

617+
/**
618+
* @return int|string
619+
*/
620+
private function unpackUint64MapKey()
621+
{
622+
if (!isset($this->buffer[$this->offset + 7])) {
623+
throw new InsufficientDataException();
624+
}
625+
626+
$num = \unpack('J', $this->buffer, $this->offset)[1];
627+
$this->offset += 8;
628+
629+
return $num >= 0 ? $num : \sprintf('%u', $num);
630+
}
631+
632+
/**
633+
* @return int
634+
*/
561635
private function unpackInt8()
562636
{
563637
if (!isset($this->buffer[$this->offset])) {
@@ -570,6 +644,9 @@ private function unpackInt8()
570644
return $num > 0x7f ? $num - 0x100 : $num;
571645
}
572646

647+
/**
648+
* @return int
649+
*/
573650
private function unpackInt16()
574651
{
575652
if (!isset($this->buffer[$this->offset + 1])) {
@@ -583,6 +660,9 @@ private function unpackInt16()
583660
return $num > 0x7fff ? $num - 0x10000 : $num;
584661
}
585662

663+
/**
664+
* @return int
665+
*/
586666
private function unpackInt32()
587667
{
588668
if (!isset($this->buffer[$this->offset + 3])) {
@@ -598,6 +678,9 @@ private function unpackInt32()
598678
return $num > 0x7fffffff ? $num - 0x100000000 : $num;
599679
}
600680

681+
/**
682+
* @return int
683+
*/
601684
private function unpackInt64()
602685
{
603686
if (!isset($this->buffer[$this->offset + 7])) {
@@ -610,6 +693,9 @@ private function unpackInt64()
610693
return $num;
611694
}
612695

696+
/**
697+
* @return float
698+
*/
613699
private function unpackFloat32()
614700
{
615701
if (!isset($this->buffer[$this->offset + 3])) {
@@ -622,6 +708,9 @@ private function unpackFloat32()
622708
return $num;
623709
}
624710

711+
/**
712+
* @return float
713+
*/
625714
private function unpackFloat64()
626715
{
627716
if (!isset($this->buffer[$this->offset + 7])) {
@@ -634,6 +723,11 @@ private function unpackFloat64()
634723
return $num;
635724
}
636725

726+
/**
727+
* @param int $size
728+
*
729+
* @return array
730+
*/
637731
private function unpackArrayData($size)
638732
{
639733
$array = [];
@@ -644,6 +738,11 @@ private function unpackArrayData($size)
644738
return $array;
645739
}
646740

741+
/**
742+
* @param int $size
743+
*
744+
* @return array
745+
*/
647746
private function unpackMapData($size)
648747
{
649748
$map = [];
@@ -654,6 +753,9 @@ private function unpackMapData($size)
654753
return $map;
655754
}
656755

756+
/**
757+
* @return int|string
758+
*/
657759
private function unpackMapKey()
658760
{
659761
if (!isset($this->buffer[$this->offset])) {
@@ -681,7 +783,7 @@ private function unpackMapKey()
681783
case 0xcc: return $this->unpackUint8();
682784
case 0xcd: return $this->unpackUint16();
683785
case 0xce: return $this->unpackUint32();
684-
case 0xcf: return $this->unpackUint64();
786+
case 0xcf: return $this->unpackUint64MapKey();
685787
// int
686788
case 0xd0: return $this->unpackInt8();
687789
case 0xd1: return $this->unpackInt16();
@@ -700,6 +802,11 @@ private function unpackMapKey()
700802
throw UnpackingFailedException::invalidMapKeyType($c);
701803
}
702804

805+
/**
806+
* @param int $length
807+
*
808+
* @return mixed
809+
*/
703810
private function unpackExtData($length)
704811
{
705812
if (!isset($this->buffer[$this->offset + $length])) { // 1 (type) + length - 1

src/Exception/PackingFailedException.php

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,9 @@
1313

1414
class PackingFailedException extends \RuntimeException
1515
{
16+
/**
17+
* @param mixed $value
18+
*/
1619
public static function unsupportedType($value) : self
1720
{
1821
return new self(\sprintf('Unsupported type "%s", maybe you forgot to register the type transformer?',

0 commit comments

Comments
 (0)