X-Git-Url: https://git.m6w6.name/?p=m6w6%2Fext-json_post;a=blobdiff_plain;f=php_json_post.c;h=77ceb8d3854fe20c208d2a3c76885223210df949;hp=6bc8c333a92324dce45e9e11ce0973ce5ba834d2;hb=c1b0270e93fc2706027296233553933d03d3fd1e;hpb=3964b8f0cd83ef3ba5de9d0b2e5e395f95404a8c diff --git a/php_json_post.c b/php_json_post.c index 6bc8c33..77ceb8d 100644 --- a/php_json_post.c +++ b/php_json_post.c @@ -25,14 +25,28 @@ ZEND_DECLARE_MODULE_GLOBALS(json_post); PHP_INI_BEGIN() - STD_PHP_INI_ENTRY("json_post.flags", "1", PHP_INI_PERDIR, OnUpdateLong, flags, zend_json_post_globals, json_post_globals) + STD_PHP_INI_ENTRY("json_post.flags", "1", PHP_INI_PERDIR, OnUpdateLong, flags, zend_json_post_globals, json_post_globals) + STD_PHP_INI_ENTRY("json_post.onerror.response", "0", PHP_INI_PERDIR, OnUpdateLong, onerror.response, zend_json_post_globals, json_post_globals) + STD_PHP_INI_ENTRY("json_post.onerror.exit", "0", PHP_INI_PERDIR, OnUpdateBool, onerror.exit, zend_json_post_globals, json_post_globals) + STD_PHP_INI_ENTRY("json_post.onerror.warning", "0", PHP_INI_PERDIR, OnUpdateBool, onerror.warning, zend_json_post_globals, json_post_globals) PHP_INI_END() static void php_json_post_init_globals(zend_json_post_globals *json_post_globals) { + memset(json_post_globals, 0, sizeof(*json_post_globals)); +#if PHP_VERSION_ID >= 50400 json_post_globals->flags = PHP_JSON_OBJECT_AS_ARRAY; +#else + json_post_globals->flags = 1; +#endif } +#ifndef TSRMLS_CC +# define TSRMLS_D +# define TSRMLS_C +# define TSRMLS_CC +#endif + PHP_MINFO_FUNCTION(json_post) { php_info_print_table_start(); @@ -42,52 +56,140 @@ PHP_MINFO_FUNCTION(json_post) DISPLAY_INI_ENTRIES(); } +#if PHP_VERSION_ID < 70000 +# undef JSON_G +# ifdef ZTS +# define JSON_G(v) TSRMG(JSON_POST_G(json_module)->globals_id_ptr, zend_json_globals *, v) +# else +# define JSON_G(v) ((zend_json_globals *) JSON_POST_G(json_module)->globals_ptr)->v +# endif +#endif + static SAPI_POST_HANDLER_FUNC(php_json_post_handler) { - zval *zarg = arg; - char *json_str = NULL; - size_t json_len = 0; + int module_number = 0; + +#if PHP_VERSION_ID >= 70000 + zend_string *json = NULL; -#if PHP_VERSION_ID >= 50600 if (SG(request_info).request_body) { /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */ php_stream_rewind(SG(request_info).request_body); - json_len = php_stream_copy_to_mem(SG(request_info).request_body, &json_str, PHP_STREAM_COPY_ALL, 0); + json = php_stream_copy_to_mem(SG(request_info).request_body, PHP_STREAM_COPY_ALL, 0); } + + if (json) { + if (json->len) { + zval tmp; + long flags = JSON_POST_G(flags); + +#ifdef PHP_JSON_THROW_ON_ERROR + /* there's no execute data, so we must ensure json_decode() is not throwing */ + flags &= ~PHP_JSON_THROW_ON_ERROR; +#endif + + ZVAL_NULL(&tmp); + php_json_decode_ex(&tmp, json->val, json->len, flags, PG(max_input_nesting_level)); + + switch (Z_TYPE(tmp)) { + case IS_OBJECT: + case IS_ARRAY: + if (zend_hash_num_elements(HASH_OF(&tmp))) { + zval_dtor(arg); + ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_POST], &tmp); + } else { + /* PHP-7.4 optimizes empty array */ + zval_ptr_dtor(&tmp); + } + break; + default: + break; + } + } + zend_string_release(json); + } + #else + + zval *zarg = arg; + char *json_str = NULL; + size_t json_len = 0; + +# if PHP_VERSION_ID >= 50600 + if (!SG(request_info).request_body) { + return; + } + + /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */ + php_stream_rewind(SG(request_info).request_body); + json_len = php_stream_copy_to_mem(SG(request_info).request_body, &json_str, PHP_STREAM_COPY_ALL, 0); +# else json_str = SG(request_info).raw_post_data; json_len = SG(request_info).raw_post_data_length; -#endif +# endif if (json_len) { zval zjson; INIT_ZVAL(zjson); + +# if PHP_VERSION_ID >= 50400 php_json_decode_ex(&zjson, json_str, json_len, JSON_POST_G(flags), PG(max_input_nesting_level) TSRMLS_CC); - if (Z_TYPE(zjson) != IS_NULL) { + if (Z_TYPE(zjson) != IS_NULL) { zval_dtor(zarg); ZVAL_COPY_VALUE(zarg, (&zjson)); +# else + php_json_decode(&zjson, json_str, json_len, (zend_bool)(JSON_POST_G(flags)&1), PG(max_input_nesting_level) TSRMLS_CC); + if (Z_TYPE(zjson) != IS_NULL) { + zval_dtor(zarg); + zarg->value = zjson.value; + Z_TYPE_P(zarg) = Z_TYPE(zjson); +# endif } } -#if PHP_VERSION_ID >= 50600 +# if PHP_VERSION_ID >= 50600 if (json_str) { efree(json_str); } +# endif #endif + + REGISTER_LONG_CONSTANT("JSON_POST_ERROR", JSON_G(error_code), CONST_CS); + + if (JSON_G(error_code)) { + if (JSON_POST_G(onerror.response)) { + sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (zend_long) JSON_POST_G(onerror.response) TSRMLS_CC); + } + if (JSON_POST_G(onerror.warning)) { + zend_error(E_WARNING, "json_post: json_decode failed with error code: %d", JSON_G(error_code)); + } + if (JSON_POST_G(onerror.exit)) { + sapi_send_headers(TSRMLS_C); + zend_bailout(); + } +#if PHP_VERSION_ID >= 70000 && PHP_VERSION_ID < 80000 + /* ext/json in PHP-7 fails to reset error_code in RINIT */ + JSON_G(error_code) = 0; +#endif + } } PHP_MINIT_FUNCTION(json_post) { - sapi_post_entry entry = {NULL, 0, NULL, NULL}; + sapi_post_entry json_post_entries[] = { + { "text/json", sizeof("text/json")-1, sapi_read_standard_form_data, php_json_post_handler }, + { "application/json", sizeof("application/json")-1, sapi_read_standard_form_data, php_json_post_handler }, + { NULL, 0, NULL, NULL } + }; - entry.post_reader = sapi_read_standard_form_data; - entry.post_handler = php_json_post_handler; - - entry.content_type = "text/json"; - entry.content_type_len = sizeof("text/json")-1; - sapi_register_post_entry(&entry TSRMLS_CC); + sapi_register_post_entries(json_post_entries TSRMLS_CC); ZEND_INIT_MODULE_GLOBALS(json_post, php_json_post_init_globals, NULL); + +#if PHP_VERSION_ID < 70000 + zend_hash_find(&module_registry, ZEND_STRS("json"), (void **) &JSON_POST_G(json_module)); +#endif + REGISTER_INI_ENTRIES(); return SUCCESS; }