summaryrefslogtreecommitdiff
path: root/ext/json/json.c
diff options
context:
space:
mode:
Diffstat (limited to 'ext/json/json.c')
-rw-r--r--ext/json/json.c31
1 files changed, 28 insertions, 3 deletions
diff --git a/ext/json/json.c b/ext/json/json.c
index fb01529711..e26c369589 100644
--- a/ext/json/json.c
+++ b/ext/json/json.c
@@ -682,7 +682,7 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len,
else
{
double d;
- int type;
+ int type, overflow_info;
long p;
RETVAL_NULL();
@@ -698,11 +698,36 @@ PHP_JSON_API void php_json_decode_ex(zval *return_value, char *str, int str_len,
RETVAL_BOOL(0);
}
- if ((type = is_numeric_string(str, str_len, &p, &d, 0)) != 0) {
+ if ((type = is_numeric_string_ex(str, str_len, &p, &d, 0, &overflow_info)) != 0) {
if (type == IS_LONG) {
RETVAL_LONG(p);
} else if (type == IS_DOUBLE) {
- RETVAL_DOUBLE(d);
+ if (options & PHP_JSON_BIGINT_AS_STRING && overflow_info) {
+ /* Within an object or array, a numeric literal is assumed
+ * to be an integer if and only if it's entirely made up of
+ * digits (exponent notation will result in the number
+ * being treated as a double). We'll match that behaviour
+ * here. */
+ int i;
+ zend_bool is_float = 0;
+
+ for (i = (str[0] == '-' ? 1 : 0); i < str_len; i++) {
+ /* Not using isdigit() because it's locale specific,
+ * but we expect JSON input to always be UTF-8. */
+ if (str[i] < '0' || str[i] > '9') {
+ is_float = 1;
+ break;
+ }
+ }
+
+ if (is_float) {
+ RETVAL_DOUBLE(d);
+ } else {
+ RETVAL_STRINGL(str, str_len, 1);
+ }
+ } else {
+ RETVAL_DOUBLE(d);
+ }
}
}