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