mirror of
https://github.com/php/php-src.git
synced 2026-04-29 03:03:26 +02:00
MFH Add json_last_error() for getting a bit of information about what failed during a decode, also fixes a segfault when we have [1}
[DOC]
This commit is contained in:
+12
-18
@@ -194,13 +194,6 @@ enum modes {
|
||||
MODE_OBJECT,
|
||||
};
|
||||
|
||||
enum error_codes {
|
||||
ERROR_DEPTH,
|
||||
ERROR_MISMATCH,
|
||||
ERROR_CTRL_CHAR,
|
||||
ERROR_SYNTAX,
|
||||
};
|
||||
|
||||
|
||||
/*
|
||||
Push a mode onto the stack. Return false if there is overflow.
|
||||
@@ -210,7 +203,7 @@ push(JSON_parser jp, int mode)
|
||||
{
|
||||
jp->top += 1;
|
||||
if (jp->top >= jp->depth) {
|
||||
jp->error = ERROR_DEPTH;
|
||||
jp->error_code = PHP_JSON_ERROR_DEPTH;
|
||||
return false;
|
||||
}
|
||||
jp->stack[jp->top] = mode;
|
||||
@@ -226,7 +219,7 @@ static int
|
||||
pop(JSON_parser jp, int mode)
|
||||
{
|
||||
if (jp->top < 0 || jp->stack[jp->top] != mode) {
|
||||
jp->error = ERROR_MISMATCH;
|
||||
jp->error_code = PHP_JSON_ERROR_STATE_MISMATCH;
|
||||
return false;
|
||||
}
|
||||
jp->top -= 1;
|
||||
@@ -252,6 +245,7 @@ new_JSON_parser(int depth)
|
||||
jp->state = GO;
|
||||
jp->depth = depth;
|
||||
jp->top = -1;
|
||||
jp->error_code = PHP_JSON_ERROR_NONE;
|
||||
jp->stack = (int*)ecalloc(depth, sizeof(int));
|
||||
push(jp, MODE_DONE);
|
||||
return jp;
|
||||
@@ -428,7 +422,7 @@ parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int
|
||||
} else {
|
||||
next_class = ascii_class[next_char];
|
||||
if (next_class <= __) {
|
||||
jp->error = ERROR_CTRL_CHAR;
|
||||
jp->error_code = PHP_JSON_ERROR_CTRL_CHAR;
|
||||
FREE_BUFFERS();
|
||||
return false;
|
||||
}
|
||||
@@ -511,9 +505,7 @@ parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int
|
||||
break;
|
||||
/* } */
|
||||
case -8:
|
||||
if (type != -1 &&
|
||||
(jp->stack[jp->top] == MODE_OBJECT ||
|
||||
jp->stack[jp->top] == MODE_ARRAY))
|
||||
if (type != -1 && jp->stack[jp->top] == MODE_OBJECT)
|
||||
{
|
||||
zval *mval;
|
||||
smart_str_0(&buf);
|
||||
@@ -541,9 +533,7 @@ parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int
|
||||
/* ] */
|
||||
case -7:
|
||||
{
|
||||
if (type != -1 &&
|
||||
(jp->stack[jp->top] == MODE_OBJECT ||
|
||||
jp->stack[jp->top] == MODE_ARRAY))
|
||||
if (type != -1 && jp->stack[jp->top] == MODE_ARRAY)
|
||||
{
|
||||
zval *mval;
|
||||
smart_str_0(&buf);
|
||||
@@ -702,7 +692,7 @@ parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int
|
||||
*/
|
||||
default:
|
||||
{
|
||||
jp->error = ERROR_SYNTAX;
|
||||
jp->error_code = PHP_JSON_ERROR_SYNTAX;
|
||||
FREE_BUFFERS();
|
||||
return false;
|
||||
}
|
||||
@@ -711,8 +701,12 @@ parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int
|
||||
}
|
||||
|
||||
FREE_BUFFERS();
|
||||
if (jp->state == OK && pop(jp, MODE_DONE)) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return jp->state == OK && pop(jp, MODE_DONE);
|
||||
jp->error_code = PHP_JSON_ERROR_SYNTAX;
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@@ -12,12 +12,20 @@ typedef struct JSON_parser_struct {
|
||||
int state;
|
||||
int depth;
|
||||
int top;
|
||||
int error;
|
||||
int error_code;
|
||||
int* stack;
|
||||
zval *the_zstack[JSON_PARSER_MAX_DEPTH];
|
||||
|
||||
} * JSON_parser;
|
||||
|
||||
enum error_codes {
|
||||
PHP_JSON_ERROR_NONE = 0,
|
||||
PHP_JSON_ERROR_DEPTH,
|
||||
PHP_JSON_ERROR_STATE_MISMATCH,
|
||||
PHP_JSON_ERROR_CTRL_CHAR,
|
||||
PHP_JSON_ERROR_SYNTAX,
|
||||
};
|
||||
|
||||
extern JSON_parser new_JSON_parser(int depth);
|
||||
extern int parse_JSON(JSON_parser jp, zval *z, unsigned short utf16_json[], int length, int assoc TSRMLS_DC);
|
||||
extern int free_JSON_parser(JSON_parser jp);
|
||||
|
||||
+40
-9
@@ -33,6 +33,7 @@
|
||||
static PHP_MINFO_FUNCTION(json);
|
||||
static PHP_FUNCTION(json_encode);
|
||||
static PHP_FUNCTION(json_decode);
|
||||
static PHP_FUNCTION(json_last_error);
|
||||
|
||||
static const char digits[] = "0123456789abcdef";
|
||||
|
||||
@@ -41,6 +42,8 @@ static const char digits[] = "0123456789abcdef";
|
||||
#define PHP_JSON_HEX_APOS (1<<2)
|
||||
#define PHP_JSON_HEX_QUOT (1<<3)
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(json)
|
||||
|
||||
/* {{{ arginfo */
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_json_encode, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, value)
|
||||
@@ -51,15 +54,16 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_json_decode, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, json)
|
||||
ZEND_ARG_INFO(0, assoc)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO(arginfo_json_last_error, 0)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
|
||||
/* {{{ json_functions[]
|
||||
*
|
||||
* Every user visible function must have an entry in json_functions[].
|
||||
*/
|
||||
/* {{{ json_functions[] */
|
||||
static const function_entry json_functions[] = {
|
||||
PHP_FE(json_encode, arginfo_json_encode)
|
||||
PHP_FE(json_decode, arginfo_json_decode)
|
||||
PHP_FE(json_last_error, arginfo_json_last_error)
|
||||
{NULL, NULL, NULL}
|
||||
};
|
||||
/* }}} */
|
||||
@@ -72,17 +76,29 @@ static PHP_MINIT_FUNCTION(json)
|
||||
REGISTER_LONG_CONSTANT("JSON_HEX_APOS", PHP_JSON_HEX_APOS, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("JSON_HEX_QUOT", PHP_JSON_HEX_QUOT, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
REGISTER_LONG_CONSTANT("JSON_ERROR_NONE", PHP_JSON_ERROR_NONE, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("JSON_ERROR_DEPTH", PHP_JSON_ERROR_DEPTH, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("JSON_ERROR_STATE_MISMATCH", PHP_JSON_ERROR_STATE_MISMATCH, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("JSON_ERROR_CTRL_CHAR", PHP_JSON_ERROR_CTRL_CHAR, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("JSON_ERROR_SYNTAX", PHP_JSON_ERROR_SYNTAX, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ PHP_GINIT_FUNCTION
|
||||
*/
|
||||
static PHP_GINIT_FUNCTION(json)
|
||||
{
|
||||
json_globals->error_code = 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ json_module_entry
|
||||
*/
|
||||
zend_module_entry json_module_entry = {
|
||||
#if ZEND_MODULE_API_NO >= 20010901
|
||||
STANDARD_MODULE_HEADER,
|
||||
#endif
|
||||
"json",
|
||||
json_functions,
|
||||
PHP_MINIT(json),
|
||||
@@ -90,10 +106,12 @@ zend_module_entry json_module_entry = {
|
||||
NULL,
|
||||
NULL,
|
||||
PHP_MINFO(json),
|
||||
#if ZEND_MODULE_API_NO >= 20010901
|
||||
PHP_JSON_VERSION,
|
||||
#endif
|
||||
STANDARD_MODULE_PROPERTIES
|
||||
PHP_MODULE_GLOBALS(json),
|
||||
PHP_GINIT(json),
|
||||
NULL,
|
||||
NULL,
|
||||
STANDARD_MODULE_PROPERTIES_EX
|
||||
};
|
||||
/* }}} */
|
||||
|
||||
@@ -533,10 +551,23 @@ static PHP_FUNCTION(json_decode)
|
||||
}
|
||||
FREE_ZVAL(z);
|
||||
efree(utf16);
|
||||
JSON_G(error_code) = jp->error_code;
|
||||
free_JSON_parser(jp);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto int json_last_error()
|
||||
Returns the error code of the last json_decode(). */
|
||||
static PHP_FUNCTION(json_last_error)
|
||||
{
|
||||
if (zend_parse_parameters_none() == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
RETURN_LONG(JSON_G(error_code));
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/*
|
||||
* Local variables:
|
||||
* tab-width: 4
|
||||
|
||||
@@ -30,6 +30,16 @@ extern zend_module_entry json_module_entry;
|
||||
#include "TSRM.h"
|
||||
#endif
|
||||
|
||||
ZEND_BEGIN_MODULE_GLOBALS(json)
|
||||
int error_code;
|
||||
ZEND_END_MODULE_GLOBALS(json)
|
||||
|
||||
#ifdef ZTS
|
||||
# define JSON_G(v) TSRMG(json_globals_id, zend_json_globals *, v)
|
||||
#else
|
||||
# define JSON_G(v) (json_globals.v)
|
||||
#endif
|
||||
|
||||
#endif /* PHP_JSON_H */
|
||||
|
||||
/*
|
||||
|
||||
@@ -0,0 +1,36 @@
|
||||
--TEST--
|
||||
json_last_error() tests
|
||||
--SKIPIF--
|
||||
<?php if (!extension_loaded("json")) print "skip"; ?>
|
||||
--FILE--
|
||||
<?php
|
||||
var_dump(json_decode("[1]"));
|
||||
var_dump(json_last_error());
|
||||
var_dump(json_decode("[[1]]", false, 2));
|
||||
var_dump(json_last_error());
|
||||
var_dump(json_decode("[1}"));
|
||||
var_dump(json_last_error());
|
||||
var_dump(json_decode('["' . chr(0) . 'abcd"]'));
|
||||
var_dump(json_last_error());
|
||||
var_dump(json_decode("[1"));
|
||||
var_dump(json_last_error());
|
||||
|
||||
|
||||
echo "Done\n";
|
||||
?>
|
||||
--EXPECT--
|
||||
array(1) {
|
||||
[0]=>
|
||||
int(1)
|
||||
}
|
||||
int(0)
|
||||
NULL
|
||||
int(1)
|
||||
NULL
|
||||
int(2)
|
||||
NULL
|
||||
int(3)
|
||||
NULL
|
||||
int(4)
|
||||
Done
|
||||
|
||||
Reference in New Issue
Block a user