From 5a22a4f1f31a44c41a518764dc9e49b113431400 Mon Sep 17 00:00:00 2001 From: Alexander Kurilo Date: Thu, 2 Aug 2018 23:47:14 +0300 Subject: [PATCH] Make surrogate sequences in JSON work on PHP 5.3 Fixes #7510 --- src/Composer/Json/JsonFormatter.php | 7 +++++++ tests/Composer/Test/Json/JsonFormatterTest.php | 14 ++++++++++++++ 2 files changed, 21 insertions(+) diff --git a/src/Composer/Json/JsonFormatter.php b/src/Composer/Json/JsonFormatter.php index 680a57baf..44acaff59 100644 --- a/src/Composer/Json/JsonFormatter.php +++ b/src/Composer/Json/JsonFormatter.php @@ -69,6 +69,13 @@ class JsonFormatter $l = strlen($match[1]); if ($l % 2) { + $code = hexdec($match[2]); + // 0xD800..0xDFFF denotes UTF-16 surrogate pair which won't be unescaped + // see https://github.com/composer/composer/issues/7510 + if (0xD800 <= $code && 0xDFFF >= $code) { + return $match[0]; + } + return str_repeat('\\', $l - 1) . mb_convert_encoding( pack('H*', $match[2]), 'UTF-8', diff --git a/tests/Composer/Test/Json/JsonFormatterTest.php b/tests/Composer/Test/Json/JsonFormatterTest.php index 7be8fafe2..fc6cf53ed 100644 --- a/tests/Composer/Test/Json/JsonFormatterTest.php +++ b/tests/Composer/Test/Json/JsonFormatterTest.php @@ -33,6 +33,20 @@ class JsonFormatterTest extends TestCase $this->assertEquals($expected, $this->getCharacterCodes($encodedData)); } + /** + * Surrogate pairs are intentionally skipped and not unescaped + * https://github.com/composer/composer/issues/7510 + */ + public function testUtf16SurrogatePair() + { + if (!extension_loaded('mbstring')) { + $this->markTestSkipped('Test requires the mbstring extension'); + } + + $escaped = '"\ud83d\ude00"'; + $this->assertEquals($escaped, JsonFormatter::format($escaped, true, true)); + } + /** * Convert string to character codes split by a plus sign * @param string $string