Skip to content

Commit 7fff851

Browse files
authored
Release v3.29.1
2 parents 35f0f4c + 18b7a60 commit 7fff851

File tree

5 files changed

+80
-4
lines changed

5 files changed

+80
-4
lines changed

CHANGELOG.md

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,15 @@
11
Changelog
22
=========
33

4+
## 3.29.1 (2023-05-10)
5+
6+
### Fixes
7+
8+
* Avoid deprecated `utf8_encode` function
9+
[gabrielrbarbosa](https://github.com/gabrielrbarbosa)
10+
[#661](https://github.com/bugsnag/bugsnag-php/pull/661)
11+
[#662](https://github.com/bugsnag/bugsnag-php/pull/662)
12+
413
## 3.29.0 (2022-10-19)
514

615
### Enhancements

src/Configuration.php

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -85,7 +85,7 @@ class Configuration implements FeatureDataStore
8585
*/
8686
protected $notifier = [
8787
'name' => 'Bugsnag PHP (Official)',
88-
'version' => '3.29.0',
88+
'version' => '3.29.1',
8989
'url' => 'https://bugsnag.com',
9090
];
9191

src/HttpClient.php

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,13 @@ class HttpClient
2727
*/
2828
protected $queue = [];
2929

30+
/**
31+
* Flags to pass to 'json_encode'.
32+
*
33+
* @var int
34+
*/
35+
private $jsonEncodeFlags = 0;
36+
3037
/**
3138
* The maximum payload size. A whole megabyte (1024 * 1024).
3239
*
@@ -59,6 +66,11 @@ public function __construct(Configuration $config, ClientInterface $guzzle)
5966
{
6067
$this->config = $config;
6168
$this->guzzle = $guzzle;
69+
70+
// substitute invalid UTF-8 characters when possible (PHP 7.2+)
71+
if (defined('JSON_INVALID_UTF8_SUBSTITUTE')) {
72+
$this->jsonEncodeFlags |= JSON_INVALID_UTF8_SUBSTITUTE;
73+
}
6274
}
6375

6476
/**
@@ -347,15 +359,15 @@ protected function deliverEvents($uri, array $data)
347359
*/
348360
protected function normalize(array $data)
349361
{
350-
$body = json_encode($data);
362+
$body = json_encode($data, $this->jsonEncodeFlags);
351363

352364
if ($this->length($body) <= static::MAX_SIZE) {
353365
return $body;
354366
}
355367

356368
unset($data['events'][0]['metaData']);
357369

358-
$body = json_encode($data);
370+
$body = json_encode($data, $this->jsonEncodeFlags);
359371

360372
if ($this->length($body) > static::MAX_SIZE) {
361373
throw new RuntimeException('Payload too large');

src/Report.php

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -848,7 +848,25 @@ protected function cleanupObj($obj, $isMetaData)
848848
}
849849

850850
if (is_string($obj)) {
851-
return (function_exists('mb_detect_encoding') && !mb_detect_encoding($obj, 'UTF-8', true)) ? utf8_encode($obj) : $obj;
851+
// on PHP 7.2+ we can use the 'JSON_INVALID_UTF8_SUBSTITUTE' flag to
852+
// substitute invalid UTF-8 characters when encoding so can return
853+
// strings as-is and let PHP handle invalid UTF-8
854+
// note: we check PHP 7.2+ specifically rather than if the flag
855+
// exists because some code defines the flag as '0' when it doesn't
856+
// exist to avoid having to check for it existing. This completely
857+
// breaks the flag as it will not function, so we can't know if the
858+
// flag can be used just from it being defined
859+
if (version_compare(PHP_VERSION, '7.2', '>=')) {
860+
return $obj;
861+
}
862+
863+
// if we have the mbstring extension available, use that to detect
864+
// encodings and handle conversions to UTF-8
865+
if (function_exists('mb_check_encoding') && !mb_check_encoding($obj, 'UTF-8')) {
866+
return mb_convert_encoding($obj, 'UTF-8', mb_list_encodings());
867+
}
868+
869+
return $obj;
852870
}
853871

854872
if (is_object($obj)) {

tests/ClientTest.php

Lines changed: 37 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1412,4 +1412,41 @@ function ($options) use ($called) {
14121412

14131413
$this->client->flush();
14141414
}
1415+
1416+
public function testCanHandleInvalidUtf8InMetadata()
1417+
{
1418+
if (version_compare(PHP_VERSION, '7.2', '>=')) {
1419+
// U+FFFD (REPLACEMENT CHARACTER)
1420+
$expectedReplacement = "\xef\xbf\xbd";
1421+
} else {
1422+
$expectedReplacement = '';
1423+
}
1424+
1425+
$this->expectGuzzlePostWithCallback(
1426+
$this->client->getNotifyEndpoint(),
1427+
function ($options) use ($expectedReplacement) {
1428+
$payload = $this->getPayloadFromGuzzleOptions($options);
1429+
1430+
$expected = [
1431+
'invalid UTF-8' => [
1432+
'c0 is not valid as the first byte' => $expectedReplacement.'AAA',
1433+
],
1434+
];
1435+
1436+
$this->assertSame($expected, $payload['events'][0]['metaData']);
1437+
1438+
return true;
1439+
}
1440+
);
1441+
1442+
$this->client->notifyException(new Exception('Something broke'), function ($report) {
1443+
$report->setMetaData([
1444+
'invalid UTF-8' => [
1445+
'c0 is not valid as the first byte' => "\xc0AAA",
1446+
],
1447+
]);
1448+
});
1449+
1450+
$this->client->flush();
1451+
}
14151452
}

0 commit comments

Comments
 (0)