Skip to content

Commit 1be9f51

Browse files
committed
json_encode: Always escape U+2028 and U+2029.
These characters are illegal in Javascript, so leaving them unescaped is risky.
1 parent 8a6f905 commit 1be9f51

File tree

2 files changed

+36
-2
lines changed

2 files changed

+36
-2
lines changed

ext/json/json_encoder.c

+8-2
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,8 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
321321

322322
do {
323323
us = (unsigned char)s[pos];
324-
if (us >= 0x80 && !(options & PHP_JSON_UNESCAPED_UNICODE)) {
325-
/* UTF-8 character */
324+
if (us >= 0x80 && (!(options & PHP_JSON_UNESCAPED_UNICODE) || us == 0xE2)) {
325+
/* UTF-8 character (and always escape U+2028/U+2029) */
326326
us = php_next_utf8_char((const unsigned char *)s, len, &pos, &status);
327327
if (status != SUCCESS) {
328328
if (buf->s) {
@@ -332,6 +332,11 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
332332
smart_str_appendl(buf, "null", 4);
333333
return;
334334
}
335+
if (us != 0x2028 && us != 0x2029 && (options & PHP_JSON_UNESCAPED_UNICODE)) {
336+
pos -= 3;
337+
us = (unsigned char)s[pos];
338+
goto unescaped_char;
339+
}
335340
/* From http://en.wikipedia.org/wiki/UTF16 */
336341
if (us >= 0x10000) {
337342
unsigned int next_us;
@@ -351,6 +356,7 @@ static void php_json_escape_string(smart_str *buf, char *s, size_t len, int opti
351356
smart_str_appendc(buf, digits[(us & 0xf0) >> 4]);
352357
smart_str_appendc(buf, digits[(us & 0xf)]);
353358
} else {
359+
unescaped_char:
354360
pos++;
355361

356362
switch (us) {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
--TEST--
2+
json_encode() tests for U+2028, U+2029
3+
--SKIPIF--
4+
<?php if (!extension_loaded("json")) print "skip"; ?>
5+
--FILE--
6+
<?php
7+
var_dump(json_encode(array("a\xC3\xA1b")));
8+
var_dump(json_encode(array("a\xC3\xA1b"), JSON_UNESCAPED_UNICODE));
9+
var_dump(json_encode("a\xE2\x80\xA7b"));
10+
var_dump(json_encode("a\xE2\x80\xA7b", JSON_UNESCAPED_UNICODE));
11+
var_dump(json_encode("a\xE2\x80\xA8b"));
12+
var_dump(json_encode("a\xE2\x80\xA8b", JSON_UNESCAPED_UNICODE));
13+
var_dump(json_encode("a\xE2\x80\xA9b"));
14+
var_dump(json_encode("a\xE2\x80\xA9b", JSON_UNESCAPED_UNICODE));
15+
var_dump(json_encode("a\xE2\x80\xAAb"));
16+
var_dump(json_encode("a\xE2\x80\xAAb", JSON_UNESCAPED_UNICODE));
17+
?>
18+
--EXPECT--
19+
string(12) "["a\u00e1b"]"
20+
string(8) "["aáb"]"
21+
string(10) ""a\u2027b""
22+
string(7) ""a‧b""
23+
string(10) ""a\u2028b""
24+
string(10) ""a\u2028b""
25+
string(10) ""a\u2029b""
26+
string(10) ""a\u2029b""
27+
string(10) ""a\u202ab""
28+
string(7) ""a‪b""

0 commit comments

Comments
 (0)