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