diff --git a/src/Modifiers/CoreModifiers.php b/src/Modifiers/CoreModifiers.php index 34267fde42a..42e3d800704 100644 --- a/src/Modifiers/CoreModifiers.php +++ b/src/Modifiers/CoreModifiers.php @@ -2802,7 +2802,15 @@ public function toBool($value, $params) */ public function toJson($value, $params) { - $options = Arr::get($params, 0) === 'pretty' ? JSON_PRETTY_PRINT : 0; + $options = 0; + + if (in_array('pretty', $params)) { + $options |= JSON_PRETTY_PRINT; + } + + if (in_array('safe', $params)) { + $options |= JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT; + } if (Compare::isQueryBuilder($value)) { $value = $value->get(); diff --git a/tests/Modifiers/ToJsonTest.php b/tests/Modifiers/ToJsonTest.php index a1632e941df..362e6a443f6 100644 --- a/tests/Modifiers/ToJsonTest.php +++ b/tests/Modifiers/ToJsonTest.php @@ -32,6 +32,43 @@ public function it_pretty_prints($input, $expected): void $this->assertEquals(json_encode(json_decode($expected, true), JSON_PRETTY_PRINT), $modified); } + #[Test] + public function it_hex_encodes_html_sensitive_characters_when_safe(): void + { + $value = ''; + $modified = $this->modify($value, ['safe']); + + $this->assertSame( + json_encode($value, JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT), + $modified, + ); + $this->assertStringNotContainsString('', $modified); + $this->assertSame($value, json_decode($modified)); + } + + #[Test] + #[DataProvider('safeParamOrderProvider')] + public function it_can_combine_pretty_and_safe(array $params): void + { + $value = ['html' => '']; + $modified = $this->modify($value, $params); + + $this->assertSame( + json_encode($value, JSON_PRETTY_PRINT | JSON_HEX_TAG | JSON_HEX_AMP | JSON_HEX_APOS | JSON_HEX_QUOT), + $modified, + ); + $this->assertStringNotContainsString('', $modified); + $this->assertSame($value, json_decode($modified, true)); + } + + public static function safeParamOrderProvider(): array + { + return [ + 'pretty then safe' => [['pretty', 'safe']], + 'safe then pretty' => [['safe', 'pretty']], + ]; + } + private function modify($value, $options = []) { return Modify::value($value)->toJson($options)->fetch();