Skip to content

Commit cf174c1

Browse files
author
Ilia Alshanetsky
committed
Added support for JSON_NUMERIC_CHECK option in json_encode() that converts
numeric strings to integers.
1 parent 1bc9247 commit cf174c1

File tree

5 files changed

+66
-12
lines changed

5 files changed

+66
-12
lines changed

NEWS

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,8 @@
3737
- Added iterator support in MySQLi. mysqli_result implements Traversable.
3838
(Andrey, Johannes)
3939
- Added scalar typehinting. (Ilia, Derick)
40+
- Added support for JSON_NUMERIC_CHECK option in json_encode() that converts
41+
numeric strings to integers. (Ilia)
4042

4143
- default_charset if not specified is now UTF-8 instead of ISO-8859-1. (Rasmus)
4244

ext/json/json.c

Lines changed: 27 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -40,15 +40,6 @@ static const char digits[] = "0123456789abcdef";
4040

4141
zend_class_entry *php_json_serializable_ce;
4242

43-
#define PHP_JSON_HEX_TAG (1<<0)
44-
#define PHP_JSON_HEX_AMP (1<<1)
45-
#define PHP_JSON_HEX_APOS (1<<2)
46-
#define PHP_JSON_HEX_QUOT (1<<3)
47-
#define PHP_JSON_FORCE_OBJECT (1<<4)
48-
49-
#define PHP_JSON_OUTPUT_ARRAY 0
50-
#define PHP_JSON_OUTPUT_OBJECT 1
51-
5243
ZEND_DECLARE_MODULE_GLOBALS(json)
5344

5445
/* {{{ arginfo */
@@ -99,6 +90,7 @@ static PHP_MINIT_FUNCTION(json)
9990
REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
10091
REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
10192
REGISTER_LONG_CONSTANT("JSON_FORCE_OBJECT", PHP_JSON_FORCE_OBJECT, CONST_CS | CONST_PERSISTENT);
93+
REGISTER_LONG_CONSTANT("JSON_NUMERIC_CHECK", PHP_JSON_NUMERIC_CHECK, CONST_CS | CONST_PERSISTENT);
10294

10395
REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
10496
REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
@@ -312,6 +304,30 @@ static void json_escape_string(smart_str *buf, char *s, int len, int options TSR
312304
return;
313305
}
314306

307+
if (options & PHP_JSON_NUMERIC_CHECK) {
308+
double d;
309+
int type;
310+
long p;
311+
312+
if ((type = is_numeric_string(s, len, &p, &d, 0)) != 0) {
313+
if (type == IS_LONG) {
314+
smart_str_append_long(buf, p);
315+
} else if (type == IS_DOUBLE) {
316+
if (!zend_isinf(d) && !zend_isnan(d)) {
317+
char *tmp;
318+
int l = spprintf(&tmp, 0, "%.*k", (int) EG(precision), d);
319+
smart_str_appendl(buf, tmp, l);
320+
efree(tmp);
321+
} else {
322+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "double %.9g does not conform to the JSON spec, encoded as 0", d);
323+
smart_str_appendc(buf, '0');
324+
}
325+
}
326+
return;
327+
}
328+
329+
}
330+
315331
utf16 = (unsigned short *) safe_emalloc(len, sizeof(unsigned short), 0);
316332

317333
len = utf8_to_utf16(utf16, s, len);
@@ -496,7 +512,7 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_
496512
smart_str_appendl(buf, d, len);
497513
efree(d);
498514
} else {
499-
zend_error(E_WARNING, "[json] (php_json_encode) double %.9g does not conform to the JSON spec, encoded as 0", dbl);
515+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "double %.9g does not conform to the JSON spec, encoded as 0", dbl);
500516
smart_str_appendc(buf, '0');
501517
}
502518
}
@@ -517,7 +533,7 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_
517533
break;
518534

519535
default:
520-
zend_error(E_WARNING, "[json] (php_json_encode) type is unsupported, encoded as null");
536+
php_error_docref(NULL TSRMLS_CC, E_WARNING, "type is unsupported, encoded as null");
521537
smart_str_appendl(buf, "null", 4);
522538
break;
523539
}

ext/json/php_json.h

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,16 @@ PHP_JSON_API void php_json_encode(smart_str *buf, zval *val, int options TSRMLS_
5151
PHP_JSON_API void php_json_decode(zval *return_value, char *str, int str_len, zend_bool assoc, long depth TSRMLS_DC);
5252
extern zend_class_entry *php_json_serializable_ce;
5353

54+
#define PHP_JSON_HEX_TAG (1<<0)
55+
#define PHP_JSON_HEX_AMP (1<<1)
56+
#define PHP_JSON_HEX_APOS (1<<2)
57+
#define PHP_JSON_HEX_QUOT (1<<3)
58+
#define PHP_JSON_FORCE_OBJECT (1<<4)
59+
#define PHP_JSON_NUMERIC_CHECK (1<<5)
60+
61+
#define PHP_JSON_OUTPUT_ARRAY 0
62+
#define PHP_JSON_OUTPUT_OBJECT 1
63+
5464
#endif /* PHP_JSON_H */
5565

5666
/*

ext/json/tests/json_encode_basic.phpt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -151,7 +151,7 @@ string(4) "null"
151151
string(4) "null"
152152
-- Iteration 26 --
153153

154-
Warning: [json] (php_json_encode) type is unsupported, encoded as null in %s on line %d
154+
Warning: json_encode(): type is unsupported, encoded as null in %s on line %d
155155
string(4) "null"
156156
-- Iteration 27 --
157157
string(82) "{"MyInt":99,"MyFloat":123.45,"MyBool":true,"MyNull":null,"MyString":"Hello World"}"
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
--TEST--
2+
Test json_encode() function with numeric flag
3+
--SKIPIF--
4+
<?php
5+
if (!extension_loaded("json")) {
6+
die('skip JSON extension not available in this build');
7+
}
8+
?>
9+
--FILE--
10+
<?php
11+
var_dump(
12+
json_encode("1", JSON_NUMERIC_CHECK),
13+
json_encode("9.4324", JSON_NUMERIC_CHECK),
14+
json_encode(array("122321", "3232595.33423"), JSON_NUMERIC_CHECK),
15+
json_encode("1"),
16+
json_encode("9.4324"),
17+
json_encode(array("122321", "3232595.33423"))
18+
);
19+
?>
20+
--EXPECT--
21+
string(1) "1"
22+
string(6) "9.4324"
23+
string(22) "[122321,3232595.33423]"
24+
string(3) ""1""
25+
string(8) ""9.4324""
26+
string(26) "["122321","3232595.33423"]"

0 commit comments

Comments
 (0)