Skip to content

Commit b477a53

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

7 files changed

+154
-14
lines changed

Diff for: src/Compressor.php

+19-2
Original file line numberDiff line numberDiff line change
@@ -42,9 +42,26 @@ 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+
// Only works with 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+
// Only works with PHP < 8.0
64+
throw new \InvalidArgumentException('Unable to initialize compressor' . $errstr); // @codeCoverageIgnore
4865
}
4966

5067
$this->context = $context;

Diff for: src/Decompressor.php

+42-6
Original file line numberDiff line numberDiff line change
@@ -41,19 +41,46 @@ 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+
// Only works with 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+
// Only works with PHP < 8.0
63+
throw new \InvalidArgumentException('Unable to initialize decompressor' . $errstr); // @codeCoverageIgnore
4764
}
4865

4966
$this->context = $context;
5067
}
5168

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

5986
if ($ret !== '') {
@@ -63,11 +90,20 @@ protected function transformData($chunk)
6390

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

103+
restore_error_handler();
104+
69105
if ($ret === false) {
70-
throw new \RuntimeException('Unable to decompress' . strstr(error_get_last()['message'], ':'));
106+
throw new \RuntimeException('Unable to decompress' . $errstr);
71107
}
72108

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

Diff for: tests/CompressorTest.php

+19
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
}

Diff for: tests/DecompressorTest.php

+20
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
}

Diff for: tests/DeflateDecompressorTest.php

+18-2
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
}

Diff for: tests/GzipDecompressorTest.php

+18-2
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
}

Diff for: tests/ZlibDecompressorTest.php

+18-2
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)