fix PHP-5-ZTS
[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 STD_PHP_INI_ENTRY("json_post.onerror.response", "0", PHP_INI_PERDIR, OnUpdateLong, onerror.response, zend_json_post_globals, json_post_globals)
30 STD_PHP_INI_ENTRY("json_post.onerror.exit", "0", PHP_INI_PERDIR, OnUpdateBool, onerror.exit, zend_json_post_globals, json_post_globals)
31 STD_PHP_INI_ENTRY("json_post.onerror.warning", "0", PHP_INI_PERDIR, OnUpdateBool, onerror.warning, zend_json_post_globals, json_post_globals)
32 PHP_INI_END()
33
34 static void php_json_post_init_globals(zend_json_post_globals *json_post_globals)
35 {
36 memset(json_post_globals, 0, sizeof(*json_post_globals));
37 #if PHP_VERSION_ID >= 50400
38 json_post_globals->flags = PHP_JSON_OBJECT_AS_ARRAY;
39 #else
40 json_post_globals->flags = 1;
41 #endif
42 }
43
44 #ifndef TSRMLS_CC
45 # define TSRMLS_D
46 # define TSRMLS_C
47 # define TSRMLS_CC
48 #endif
49
50 PHP_MINFO_FUNCTION(json_post)
51 {
52 php_info_print_table_start();
53 php_info_print_table_header(2, "json_post support", "enabled");
54 php_info_print_table_end();
55
56 DISPLAY_INI_ENTRIES();
57 }
58
59 #if PHP_VERSION_ID < 70000
60 # undef JSON_G
61 # ifdef ZTS
62 # define JSON_G(v) TSRMG(*JSON_POST_G(json_module)->globals_id_ptr, zend_json_globals *, v)
63 # else
64 # define JSON_G(v) ((zend_json_globals *) JSON_POST_G(json_module)->globals_ptr)->v
65 # endif
66 #endif
67
68 static SAPI_POST_HANDLER_FUNC(php_json_post_handler)
69 {
70 int module_number = 0;
71
72 #if PHP_VERSION_ID >= 70000
73 zend_string *json = NULL;
74
75 if (SG(request_info).request_body) {
76 /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
77 php_stream_rewind(SG(request_info).request_body);
78 json = php_stream_copy_to_mem(SG(request_info).request_body, PHP_STREAM_COPY_ALL, 0);
79 }
80
81 if (json) {
82 if (json->len) {
83 zval tmp;
84 long flags = JSON_POST_G(flags);
85
86 #ifdef PHP_JSON_THROW_ON_ERROR
87 /* there's no execute data, so we must ensure json_decode() is not throwing */
88 flags &= ~PHP_JSON_THROW_ON_ERROR;
89 #endif
90
91 ZVAL_NULL(&tmp);
92 php_json_decode_ex(&tmp, json->val, json->len, flags, PG(max_input_nesting_level));
93
94 switch (Z_TYPE(tmp)) {
95 case IS_OBJECT:
96 case IS_ARRAY:
97 if (zend_hash_num_elements(HASH_OF(&tmp))) {
98 zval_dtor(arg);
99 ZVAL_COPY_VALUE(&PG(http_globals)[TRACK_VARS_POST], &tmp);
100 } else {
101 /* PHP-7.4 optimizes empty array */
102 zval_ptr_dtor(&tmp);
103 }
104 break;
105 default:
106 break;
107 }
108 }
109 zend_string_release(json);
110 }
111
112 #else
113
114 zval *zarg = arg;
115 char *json_str = NULL;
116 size_t json_len = 0;
117
118 # if PHP_VERSION_ID >= 50600
119 if (!SG(request_info).request_body) {
120 return;
121 }
122
123 /* FG(stream_wrappers) not initialized yet, so we cannot use php://input */
124 php_stream_rewind(SG(request_info).request_body);
125 json_len = php_stream_copy_to_mem(SG(request_info).request_body, &json_str, PHP_STREAM_COPY_ALL, 0);
126 # else
127 json_str = SG(request_info).raw_post_data;
128 json_len = SG(request_info).raw_post_data_length;
129 # endif
130
131 if (json_len) {
132 zval zjson;
133
134 INIT_ZVAL(zjson);
135
136 # if PHP_VERSION_ID >= 50400
137 php_json_decode_ex(&zjson, json_str, json_len, JSON_POST_G(flags), PG(max_input_nesting_level) TSRMLS_CC);
138 if (Z_TYPE(zjson) != IS_NULL) {
139 zval_dtor(zarg);
140 ZVAL_COPY_VALUE(zarg, (&zjson));
141 # else
142 php_json_decode(&zjson, json_str, json_len, (zend_bool)(JSON_POST_G(flags)&1), PG(max_input_nesting_level) TSRMLS_CC);
143 if (Z_TYPE(zjson) != IS_NULL) {
144 zval_dtor(zarg);
145 zarg->value = zjson.value;
146 Z_TYPE_P(zarg) = Z_TYPE(zjson);
147 # endif
148 }
149 }
150 # if PHP_VERSION_ID >= 50600
151 if (json_str) {
152 efree(json_str);
153 }
154 # endif
155 #endif
156
157 REGISTER_LONG_CONSTANT("JSON_POST_ERROR", JSON_G(error_code), CONST_CS);
158
159 if (JSON_G(error_code)) {
160 if (JSON_POST_G(onerror.response)) {
161 sapi_header_op(SAPI_HEADER_SET_STATUS, (void *) (zend_long) JSON_POST_G(onerror.response) TSRMLS_CC);
162 }
163 if (JSON_POST_G(onerror.warning)) {
164 zend_error(E_WARNING, "json_post: json_decode failed with error code: %d", JSON_G(error_code));
165 }
166 if (JSON_POST_G(onerror.exit)) {
167 sapi_send_headers(TSRMLS_C);
168 zend_bailout();
169 }
170 #if PHP_VERSION_ID >= 70000 && PHP_VERSION_ID < 80000
171 /* ext/json in PHP-7 fails to reset error_code in RINIT */
172 JSON_G(error_code) = 0;
173 #endif
174 }
175 }
176
177 PHP_MINIT_FUNCTION(json_post)
178 {
179 sapi_post_entry json_post_entries[] = {
180 { "text/json", sizeof("text/json")-1, sapi_read_standard_form_data, php_json_post_handler },
181 { "application/json", sizeof("application/json")-1, sapi_read_standard_form_data, php_json_post_handler },
182 { NULL, 0, NULL, NULL }
183 };
184
185 sapi_register_post_entries(json_post_entries TSRMLS_CC);
186
187 ZEND_INIT_MODULE_GLOBALS(json_post, php_json_post_init_globals, NULL);
188
189 #if PHP_VERSION_ID < 70000
190 zend_hash_find(&module_registry, ZEND_STRS("json"), (void **) &JSON_POST_G(json_module));
191 #endif
192
193 REGISTER_INI_ENTRIES();
194 return SUCCESS;
195 }
196
197 PHP_MSHUTDOWN_FUNCTION(json_post)
198 {
199 UNREGISTER_INI_ENTRIES();
200
201 return SUCCESS;
202 }
203
204 zend_function_entry json_post_functions[] = {
205 {0}
206 };
207
208 static zend_module_dep json_post_module_deps[] = {
209 ZEND_MOD_REQUIRED("json")
210 {NULL, NULL, NULL, 0}
211 };
212
213 zend_module_entry json_post_module_entry = {
214 STANDARD_MODULE_HEADER_EX,
215 NULL,
216 json_post_module_deps,
217 "json_post",
218 json_post_functions,
219 PHP_MINIT(json_post),
220 PHP_MSHUTDOWN(json_post),
221 NULL,
222 NULL,
223 PHP_MINFO(json_post),
224 PHP_JSON_POST_VERSION,
225 STANDARD_MODULE_PROPERTIES
226 };
227 /* }}} */
228
229 #ifdef COMPILE_DL_JSON_POST
230 ZEND_GET_MODULE(json_post)
231 #endif
232
233 /*
234 * Local variables:
235 * tab-width: 4
236 * c-basic-offset: 4
237 * End:
238 * vim600: noet sw=4 ts=4 fdm=marker
239 * vim<600: noet sw=4 ts=4
240 */