fix #1: Segfault on PHP 7.4 with empty array
[m6w6/ext-json_post] / php_json_post.c
1 /*
2 +--------------------------------------------------------------------+
3 | PECL :: json_post |
4 +--------------------------------------------------------------------+
5 | Redistribution and use in source and binary forms, with or without |
6 | modification, are permitted provided that the conditions mentioned |
7 | in the accompanying LICENSE file are met. |
8 +--------------------------------------------------------------------+
9 | Copyright (c) 2015, Michael Wallner <mike@php.net> |
10 +--------------------------------------------------------------------+
11 */
12
13
14 #ifdef HAVE_CONFIG_H
15 # include "config.h"
16 #endif
17
18 #include "php.h"
19 #include "php_ini.h"
20 #include "ext/standard/info.h"
21 #include "ext/json/php_json.h"
22 #include "php_json_post.h"
23 #include "SAPI.h"
24
25 ZEND_DECLARE_MODULE_GLOBALS(json_post);
26
27 PHP_INI_BEGIN()
28 STD_PHP_INI_ENTRY("json_post.flags", "1", PHP_INI_PERDIR, OnUpdateLong, flags, zend_json_post_globals, json_post_globals)
29 PHP_INI_END()
30
31 static void php_json_post_init_globals(zend_json_post_globals *json_post_globals)
32 {
33 #if PHP_VERSION_ID >= 50400
34 json_post_globals->flags = PHP_JSON_OBJECT_AS_ARRAY;
35 #else
36 json_post_globals->flags = 1;
37 #endif
38 }
39
40 PHP_MINFO_FUNCTION(json_post)
41 {
42 php_info_print_table_start();
43 php_info_print_table_header(2, "json_post support", "enabled");
44 php_info_print_table_end();
45
46 DISPLAY_INI_ENTRIES();
47 }
48
49 #if PHP_VERSION_ID >= 70000
50 static SAPI_POST_HANDLER_FUNC(php_json_post_handler)
51 {
52 zend_string *json = NULL;
53
54 if (SG(request_info).request_body) {
55 /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
56 php_stream_rewind(SG(request_info).request_body);
57 json = php_stream_copy_to_mem(SG(request_info).request_body, PHP_STREAM_COPY_ALL, 0);
58 }
59
60 if (json) {
61 if (json->len) {
62 zval tmp;
63
64 ZVAL_NULL(&tmp);
65
66 php_json_decode_ex(&tmp, json->val, json->len, JSON_POST_G(flags), PG(max_input_nesting_level));
67
68 switch (Z_TYPE(tmp)) {
69 case IS_OBJECT:
70 case IS_ARRAY:
71 if (zend_hash_num_elements(HASH_OF(&tmp))) {
72 zval_dtor(arg);
73 ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_POST], &tmp);
74 } else {
75 /* PHP-7.4 optimizes empty array */
76 zval_ptr_dtor(&tmp);
77 }
78 break;
79 default:
80 break;
81 }
82 }
83 zend_string_release(json);
84 }
85 }
86
87 #else
88
89 static SAPI_POST_HANDLER_FUNC(php_json_post_handler)
90 {
91 zval *zarg = arg;
92 char *json_str = NULL;
93 size_t json_len = 0;
94
95 # if PHP_VERSION_ID >= 50600
96 if (!SG(request_info).request_body) {
97 return;
98 }
99
100 /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
101 php_stream_rewind(SG(request_info).request_body);
102 json_len = php_stream_copy_to_mem(SG(request_info).request_body, &json_str, PHP_STREAM_COPY_ALL, 0);
103 # else
104 json_str = SG(request_info).raw_post_data;
105 json_len = SG(request_info).raw_post_data_length;
106 # endif
107
108 if (json_len) {
109 zval zjson;
110
111 INIT_ZVAL(zjson);
112
113 # if PHP_VERSION_ID >= 50400
114 php_json_decode_ex(&zjson, json_str, json_len, JSON_POST_G(flags), PG(max_input_nesting_level) TSRMLS_CC);
115 if (Z_TYPE(zjson) != IS_NULL) {
116 zval_dtor(zarg);
117 ZVAL_COPY_VALUE(zarg, (&zjson));
118 # else
119 php_json_decode(&zjson, json_str, json_len, (zend_bool)(JSON_POST_G(flags)&1), PG(max_input_nesting_level) TSRMLS_CC);
120 if (Z_TYPE(zjson) != IS_NULL) {
121 zval_dtor(zarg);
122 zarg->value = zjson.value;
123 Z_TYPE_P(zarg) = Z_TYPE(zjson);
124 # endif
125 }
126 }
127 # if PHP_VERSION_ID >= 50600
128 if (json_str) {
129 efree(json_str);
130 }
131 # endif
132 }
133
134 #endif
135
136 PHP_MINIT_FUNCTION(json_post)
137 {
138 sapi_post_entry json_post_entries[] = {
139 { "text/json", sizeof("text/json")-1, sapi_read_standard_form_data, php_json_post_handler },
140 { "application/json", sizeof("application/json")-1, sapi_read_standard_form_data, php_json_post_handler },
141 { NULL, 0, NULL, NULL }
142 };
143
144 #ifndef TSRMLS_CC
145 # define TSRMLS_CC
146 #endif
147 sapi_register_post_entries(json_post_entries TSRMLS_CC);
148
149 ZEND_INIT_MODULE_GLOBALS(json_post, php_json_post_init_globals, NULL);
150 REGISTER_INI_ENTRIES();
151 return SUCCESS;
152 }
153
154 PHP_MSHUTDOWN_FUNCTION(json_post)
155 {
156 UNREGISTER_INI_ENTRIES();
157
158 return SUCCESS;
159 }
160
161 zend_function_entry json_post_functions[] = {
162 {0}
163 };
164
165 static zend_module_dep json_post_module_deps[] = {
166 ZEND_MOD_REQUIRED("json")
167 {NULL, NULL, NULL, 0}
168 };
169
170 zend_module_entry json_post_module_entry = {
171 STANDARD_MODULE_HEADER_EX,
172 NULL,
173 json_post_module_deps,
174 "json_post",
175 json_post_functions,
176 PHP_MINIT(json_post),
177 PHP_MSHUTDOWN(json_post),
178 NULL,
179 NULL,
180 PHP_MINFO(json_post),
181 PHP_JSON_POST_VERSION,
182 STANDARD_MODULE_PROPERTIES
183 };
184 /* }}} */
185
186 #ifdef COMPILE_DL_JSON_POST
187 ZEND_GET_MODULE(json_post)
188 #endif
189
190 /*
191 * Local variables:
192 * tab-width: 4
193 * c-basic-offset: 4
194 * End:
195 * vim600: noet sw=4 ts=4 fdm=marker
196 * vim<600: noet sw=4 ts=4
197 */