Skip to content

Commit 3d41fa5

Browse files
committed
Improve error reporting when custom error handler is used
1 parent 3c12eaf commit 3d41fa5

File tree

7 files changed

+152
-14
lines changed

7 files changed

+152
-14
lines changed

src/Compressor.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,25 @@ final class Compressor extends TransformStream
4242
*/
4343
public function __construct($encoding, $level = -1)
4444
{
45-
$context = @deflate_init($encoding, ['level' => $level]);
45+
$errstr = '';
46+
set_error_handler(function ($_, $error) use (&$errstr) {
47+
// Match errstr from PHP's warning message.
48+
// inflate_init(): encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE
49+
$errstr = strstr($error, ':'); // @codeCoverageIgnore
50+
});
51+
52+
try {
53+
$context = deflate_init($encoding, ['level' => $level]);
54+
} catch (\ValueError $e) { // @codeCoverageIgnoreStart
55+
// Throws ValueError on PHP 8.0+
56+
restore_error_handler();
57+
throw $e;
58+
} // @codeCoverageIgnoreEnd
59+
60+
restore_error_handler();
61+
4662
if ($context === false) {
47-
throw new \InvalidArgumentException('Unable to initialize compressor' . strstr(error_get_last()['message'], ':'));
63+
throw new \InvalidArgumentException('Unable to initialize compressor' . $errstr); // @codeCoverageIgnore
4864
}
4965

5066
$this->context = $context;

src/Decompressor.php

Lines changed: 41 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,45 @@ final class Decompressor extends TransformStream
4141
*/
4242
public function __construct($encoding)
4343
{
44-
$context = @inflate_init($encoding);
44+
$errstr = '';
45+
set_error_handler(function ($_, $error) use (&$errstr) {
46+
// Match errstr from PHP's warning message.
47+
// inflate_init(): encoding mode must be ZLIB_ENCODING_RAW, ZLIB_ENCODING_GZIP or ZLIB_ENCODING_DEFLATE
48+
$errstr = strstr($error, ':'); // @codeCoverageIgnore
49+
});
50+
51+
try {
52+
$context = inflate_init($encoding);
53+
} catch (\ValueError $e) { // @codeCoverageIgnoreStart
54+
// Throws ValueError on PHP 8.0+
55+
restore_error_handler();
56+
throw $e;
57+
} // @codeCoverageIgnoreEnd
58+
59+
restore_error_handler();
60+
4561
if ($context === false) {
46-
throw new \InvalidArgumentException('Unable to initialize decompressor' . strstr(error_get_last()['message'], ':'));
62+
throw new \InvalidArgumentException('Unable to initialize decompressor' . $errstr); // @codeCoverageIgnore
4763
}
4864

4965
$this->context = $context;
5066
}
5167

5268
protected function transformData($chunk)
5369
{
54-
$ret = @inflate_add($this->context, $chunk);
70+
$errstr = '';
71+
set_error_handler(function ($_, $error) use (&$errstr) {
72+
// Match errstr from PHP's warning message.
73+
// inflate_add(): data error
74+
$errstr = strstr($error, ':');
75+
});
76+
77+
$ret = inflate_add($this->context, $chunk);
78+
79+
restore_error_handler();
80+
5581
if ($ret === false) {
56-
throw new \RuntimeException('Unable to decompress' . strstr(error_get_last()['message'], ':'));
82+
throw new \RuntimeException('Unable to decompress' . $errstr);
5783
}
5884

5985
if ($ret !== '') {
@@ -63,11 +89,20 @@ protected function transformData($chunk)
6389

6490
protected function transformEnd($chunk)
6591
{
66-
$ret = @inflate_add($this->context, $chunk, ZLIB_FINISH);
92+
$errstr = '';
93+
set_error_handler(function ($_, $error) use (&$errstr) {
94+
// Match errstr from PHP's warning message.
95+
// inflate_add(): data error
96+
$errstr = strstr($error, ':');
97+
});
98+
99+
$ret = inflate_add($this->context, $chunk, ZLIB_FINISH);
67100
$this->context = null;
68101

102+
restore_error_handler();
103+
69104
if ($ret === false) {
70-
throw new \RuntimeException('Unable to decompress' . strstr(error_get_last()['message'], ':'));
105+
throw new \RuntimeException('Unable to decompress' . $errstr);
71106
}
72107

73108
if ($ret !== '') {

tests/CompressorTest.php

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,23 @@ public function testCtorThrowsForInvalidEncoding()
1111
$this->expectException(PHP_VERSION_ID >= 80000 ? \ValueError::class : \InvalidArgumentException::class);
1212
new Compressor(0);
1313
}
14+
15+
public function testCtorThrowsForInvalidEncodingAndUnsetsUsedErrorHandler()
16+
{
17+
$handler = set_error_handler(function(){});
18+
19+
restore_error_handler();
20+
21+
try {
22+
new Compressor(0);
23+
} catch (\ValueError $e) {
24+
// handle Error to unset Error handler afterwards (PHP >= 8.0)
25+
} catch (\InvalidArgumentException $e) {
26+
// handle Error to unset Error handler afterwards (PHP < 8.0)
27+
}
28+
$checkHandler = set_error_handler(function(){});
29+
restore_error_handler();
30+
31+
$this->assertEquals($handler, $checkHandler);
32+
}
1433
}

tests/DecompressorTest.php

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,4 +11,24 @@ public function testCtorThrowsForInvalidEncoding()
1111
$this->expectException(PHP_VERSION_ID >= 80000 ? \ValueError::class : \InvalidArgumentException::class);
1212
new Decompressor(0);
1313
}
14+
15+
public function testCtorThrowsForInvalidEncodingAndUnsetsUsedErrorHandler()
16+
{
17+
$handler = set_error_handler(function(){});
18+
19+
restore_error_handler();
20+
21+
try {
22+
new Decompressor(0);
23+
} catch (\ValueError $e) {
24+
// handle Error to unset Error handler afterwards (PHP >= 8.0)
25+
} catch (\InvalidArgumentException $e) {
26+
// handle Error to unset Error handler afterwards (PHP < 8.0)
27+
}
28+
29+
$checkHandler = set_error_handler(function(){});
30+
restore_error_handler();
31+
32+
$this->assertEquals($handler, $checkHandler);
33+
}
1434
}

tests/DeflateDecompressorTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,35 @@ public function testInflateBig()
5353
$this->assertEquals($data, $buffered);
5454
}
5555

56-
public function testDecompressInvalidDataEmitsError()
56+
public function testDecompressInvalidDataEmitsErrorWithoutCallingCustomErrorHandler()
5757
{
5858
$this->decompressor->on('data', $this->expectCallableNever());
5959
$this->decompressor->on('error', $this->expectCallableOnce());
6060

61+
$error = null;
62+
set_error_handler(function ($_, $errstr) use (&$error) {
63+
$error = $errstr;
64+
});
65+
6166
$this->decompressor->write('invalid');
67+
68+
restore_error_handler();
69+
$this->assertNull($error);
6270
}
6371

64-
public function testDecompressInvalidOnEndEmitsError()
72+
public function testDecompressInvalidOnEndEmitsErrorWithoutCallingCustomErrorHandler()
6573
{
6674
$this->decompressor->on('data', $this->expectCallableNever());
6775
$this->decompressor->on('error', $this->expectCallableOnce());
6876

77+
$error = null;
78+
set_error_handler(function ($_, $errstr) use (&$error) {
79+
$error = $errstr;
80+
});
81+
6982
$this->decompressor->end('invalid');
83+
84+
restore_error_handler();
85+
$this->assertNull($error);
7086
}
7187
}

tests/GzipDecompressorTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,35 @@ public function testDecompressBig()
5353
$this->assertEquals($data, $buffered);
5454
}
5555

56-
public function testDecompressInvalidDataEmitsError()
56+
public function testDecompressInvalidDataEmitsErrorWithoutCallingCustomErrorHandler()
5757
{
5858
$this->decompressor->on('data', $this->expectCallableNever());
5959
$this->decompressor->on('error', $this->expectCallableOnce());
6060

61+
$error = null;
62+
set_error_handler(function ($_, $errstr) use (&$error) {
63+
$error = $errstr;
64+
});
65+
6166
$this->decompressor->write('invalid');
67+
68+
restore_error_handler();
69+
$this->assertNull($error);
6270
}
6371

64-
public function testDecompressInvalidOnEndEmitsError()
72+
public function testDecompressInvalidOnEndEmitsErrorWithoutCallingCustomErrorHandler()
6573
{
6674
$this->decompressor->on('data', $this->expectCallableNever());
6775
$this->decompressor->on('error', $this->expectCallableOnce());
6876

77+
$error = null;
78+
set_error_handler(function ($_, $errstr) use (&$error) {
79+
$error = $errstr;
80+
});
81+
6982
$this->decompressor->end('invalid');
83+
84+
restore_error_handler();
85+
$this->assertNull($error);
7086
}
7187
}

tests/ZlibDecompressorTest.php

Lines changed: 18 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,19 +53,35 @@ public function testDecompressBig()
5353
$this->assertEquals($data, $buffered);
5454
}
5555

56-
public function testDecompressInvalidDataEmitsError()
56+
public function testDecompressInvalidDataEmitsErrorWithoutCallingCustomErrorHandler()
5757
{
5858
$this->decompressor->on('data', $this->expectCallableNever());
5959
$this->decompressor->on('error', $this->expectCallableOnce());
6060

61+
$error = null;
62+
set_error_handler(function ($_, $errstr) use (&$error) {
63+
$error = $errstr;
64+
});
65+
6166
$this->decompressor->write('invalid');
67+
68+
restore_error_handler();
69+
$this->assertNull($error);
6270
}
6371

64-
public function testDecompressInvalidOnEndEmitsError()
72+
public function testDecompressInvalidOnEndEmitsErrorWithoutCallingCustomErrorHandler()
6573
{
6674
$this->decompressor->on('data', $this->expectCallableNever());
6775
$this->decompressor->on('error', $this->expectCallableOnce());
6876

77+
$error = null;
78+
set_error_handler(function ($_, $errstr) use (&$error) {
79+
$error = $errstr;
80+
});
81+
6982
$this->decompressor->end('invalid');
83+
84+
restore_error_handler();
85+
$this->assertNull($error);
7086
}
7187
}

0 commit comments

Comments
 (0)