]> granicus.if.org Git - php/commitdiff
Add json_last_error() for getting a bit of information about what failed during a...
authorScott MacVicar <scottmac@php.net>
Fri, 19 Dec 2008 02:00:59 +0000 (02:00 +0000)
committerScott MacVicar <scottmac@php.net>
Fri, 19 Dec 2008 02:00:59 +0000 (02:00 +0000)
[DOC]

ext/json/JSON_parser.c
ext/json/JSON_parser.h
ext/json/json.c
ext/json/php_json.h
ext/json/tests/007.phpt [new file with mode: 0644]

index 2c4dd9a5f3fba33554f5e45b1127cc5066ae4e07..c4cb6ca582ce189bfddbba1be16e99e71d6dee2f 100644 (file)
@@ -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,11 +701,14 @@ 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;
 }
 
-
 /*
  * Local variables:
  * tab-width: 4
index d95f1ce667efd3c13fca0b0e2d40c37d70e659ee..a4bc9e50c38e011c106504eb793c75d84abfcdb6 100644 (file)
@@ -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);
index fea249a65d69ab0313d3cf2a21e0549f6a0de3e4..e84e5abc565f40cfc2db92f371af73a34b8cf290 100644 (file)
@@ -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,24 +42,28 @@ 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)
+       ZEND_ARG_INFO(0, options)
 ZEND_END_ARG_INFO()
 
 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}
 };
 /* }}} */
@@ -71,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),
@@ -89,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
 };
 /* }}} */
 
@@ -580,10 +599,23 @@ static PHP_FUNCTION(json_decode)
        if (str_type == IS_STRING) {
                efree(utf16);
        }
+       JSON_G(error_code) = jp->error_code;
        free_JSON_parser(jp);
 }
 /* }}} */
 
+/* {{{ proto int json_last_error() U
+   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
index dfc9427622863b758e830eddfe0ac85a949f3b83..8b86a99f712a9debdf865b7024af42e50a55d922 100644 (file)
@@ -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 */
 
 /*
diff --git a/ext/json/tests/007.phpt b/ext/json/tests/007.phpt
new file mode 100644 (file)
index 0000000..9ee190a
--- /dev/null
@@ -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
+