PluginProbe ʕ •ᴥ•ʔ
WooCommerce / 10.9.4
WooCommerce v10.9.4
10.9.4 10.9.3 10.9.2 10.9.1 10.9.0 10.9.0-rc.1 10.9.0-beta.2 10.9.0-beta.1 10.8.1 10.8.0 10.8.0-rc.1 10.8.0-beta.2 10.8.0-beta.1 7.8.0-beta.1 7.8.0-beta.2 7.8.0-rc.1 7.8.0-rc.2 7.8.1 7.8.2 7.8.3 7.8.4 7.9.0 7.9.0-beta.1 7.9.0-beta.2 7.9.0-rc.2 7.9.0-rc.3 7.9.1 7.9.2 8.0.0 8.0.0-beta.1 8.0.0-beta.2 8.0.0-rc.1 8.0.0-rc.2 8.0.1 8.0.2 8.0.3 8.0.4 8.0.5 8.1.0 8.1.0-beta.1 8.1.0-rc.1 8.1.0-rc.2 8.1.1 8.1.2 8.1.3 8.1.4 8.2.0 8.2.0-beta.1 8.2.0-rc.1 8.2.0-rc.2 8.2.1 8.2.2 8.2.3 8.2.4 8.2.5 8.3.0 8.3.0-beta.1 8.3.0-rc.1 8.3.0-rc.2 8.3.1 8.3.2 8.3.3 8.3.4 8.4.0 8.4.0-beta.1 8.4.0-rc.1 8.4.1 8.4.2 8.4.3 8.5.0 8.5.0-beta.1 8.5.0-rc.1 8.5.1 8.5.2 8.5.3 8.5.4 8.5.5 8.6.0 8.6.0-beta.1 8.6.0-rc.1 8.6.1 8.6.2 8.6.3 8.6.4 8.7.0 8.7.0-beta.1 8.7.0-beta.2 8.7.0-rc.1 8.7.1 8.7.2 8.7.3 8.8.0 8.8.0-beta.1 8.8.0-rc.1 8.8.1 8.8.2 8.8.3 8.8.4 8.8.5 8.8.6 8.8.7 8.9.0 8.9.0-beta.1 8.9.0-rc.1 8.9.1 8.9.2 8.9.3 8.9.4 8.9.5 9.0.0 9.0.0-beta.1 9.0.0-beta.2 9.0.0-rc.1 9.0.1 9.0.2 9.0.3 9.0.4 9.1.0 9.1.0-beta.1 9.1.0-rc.1 9.1.1 9.1.2 9.1.3 9.1.4 9.1.5 9.1.6 9.2.0 9.2.0-beta.1 9.2.0-rc.1 9.2.1 9.2.2 9.2.3 9.2.4 9.2.5 9.3.0 9.3.0-beta.1 9.3.0-rc.1 9.3.1 9.3.2 9.3.3 9.3.4 9.3.5 9.3.6 9.4.0 9.4.0-beta.1 9.4.0-beta.2 9.4.0-rc.1 9.4.0-rc.2 9.4.0-rc.3 9.4.0-rc.4 9.4.1 9.4.2 9.4.3 9.4.4 9.4.5 9.5.0 9.5.0-beta.1 9.5.0-beta.2 9.5.0-rc.1 9.5.1 9.5.2 9.5.3 9.5.4 9.6.0 9.6.0-beta.1 9.6.0-beta.2 9.6.0-rc.1 9.6.1 9.6.2 9.6.3 9.6.4 9.7.0 9.7.0-beta.1 9.7.0-rc.1 9.7.1 9.7.2 9.7.3 9.8.0 9.8.0-beta.1 9.8.0-rc.1 9.8.1 9.8.2 9.8.3 9.8.4 9.8.5 9.8.6 9.8.7 9.9.0 9.9.0-beta.1 9.9.0-rc.1 9.9.1 9.9.2 9.9.3 9.9.4 9.9.5 9.9.6 9.9.7 3.7.3 7.1.2 3.8.0 7.2.0 3.8.0-beta.1 7.2.0-beta.1 3.8.0-rc.1 7.2.0-beta.2 3.8.0-rc.2 7.2.0-rc.1 3.8.1 7.2.0-rc.2 3.8.2 7.2.1 3.8.3 7.2.2 3.9.0 7.2.3 3.9.0-beta.1 7.2.4 3.9.0-beta.2 7.3.0 3.9.0-rc.1 7.3.0-beta.1 3.9.0-rc.2 7.3.0-beta.2 3.9.0-rc.3 7.3.0-rc.1 3.9.0-rc.4 7.3.0-rc.2 3.9.1 7.3.1 3.9.2 7.4.0 3.9.3 7.4.0-beta.1 3.9.4 7.4.0-beta.2 3.9.5 7.4.0-rc.1 4.0.0 7.4.0-rc.2 4.0.0-beta.1 7.4.1 4.0.0-rc.1 7.4.2 4.0.0-rc.2 7.5.0 4.0.1 7.5.0-beta.1 4.0.2 7.5.0-beta.2 4.0.3 7.5.0-rc.1 4.0.4 7.5.1 4.1.0 7.5.2 4.1.0-beta.1 7.6.0 4.1.0-beta.2 7.6.0-beta.1 4.1.0-rc.1 7.6.0-beta.2 4.1.0-rc.2 7.6.0-rc.1 4.1.1 7.6.0-rc.2 4.1.2 7.6.0-rc.3 4.1.3 7.6.1 4.1.4 7.6.2 4.2.0 7.7.0 4.2.0-RC.1 7.7.0-beta.1 4.2.0-RC.2 7.7.0-beta.2 4.2.0-beta.1 7.7.0-rc.1 4.2.1 7.7.1 4.2.2 7.7.2 4.2.3 7.7.3 4.2.4 7.8.0 4.2.5 4.3.0 4.3.0-beta.1 4.3.0-rc.1 4.3.0-rc.2 4.3.0-rc.3 4.3.1 4.3.2 4.3.3 4.3.4 4.3.5 4.3.6 4.4.0 4.4.0-beta.1 4.4.0-rc.1 4.4.1 4.4.2 4.4.3 4.4.4 4.5.0 4.5.0-beta.1 4.5.0-rc.1 4.5.0-rc.3 4.5.1 4.5.2 4.5.3 4.5.4 4.5.5 4.6.0 4.6.0-beta.1 4.6.0-rc.1 4.6.1 4.6.2 4.6.3 4.6.4 4.6.5 4.7.0 4.7.0-beta.1 4.7.0-beta.2 4.7.0-rc.1 4.7.1 4.7.1-beta.1 4.7.2 4.7.3 4.7.4 4.8.0 4.8.0-beta.1 4.8.0-rc.1 4.8.0-rc.2 4.8.1 4.8.2 4.8.3 4.9.0 4.9.0-beta.1 4.9.0-rc.1 4.9.0-rc.2 4.9.1 4.9.2 4.9.3 4.9.4 4.9.5 5.0.0 5.0.0-beta.1 5.0.0-beta.2 5.0.0-rc.1 5.0.0-rc.2 5.0.0-rc.3 5.0.1 5.0.2 5.0.3 5.1.0 5.1.0-beta.1 5.1.0-rc.1 trunk 5.1.1 10.0.0 5.1.2 10.0.0-rc.1 5.1.3 10.0.0-rc.2 5.2.0 10.0.1 5.2.0-beta.1 10.0.2 5.2.0-rc.1 10.0.3 5.2.0-rc.2 10.0.4 5.2.1 10.0.5 5.2.2 10.0.6 5.2.3 10.1.0 5.2.4 10.1.0-rc.1 5.2.5 10.1.0-rc.2 5.3.0 10.1.0-rc.3 5.3.0-beta.1 10.1.0-rc.4 5.3.0-rc.1 10.1.1 5.3.0-rc.2 10.1.2 5.3.1 10.1.3 5.3.2 10.1.4 5.3.3 10.2.0 5.4.0 10.2.0-beta.1 5.4.0-beta.1 10.2.0-beta.2 5.4.0-rc.1 10.2.0-rc.1 5.4.1 10.2.1 5.4.2 10.2.2 5.4.3 10.2.3 5.4.4 10.2.4 5.4.5 10.3.0 5.5.0 10.3.0-beta.1 5.5.0-beta.1 10.3.0-beta.2 5.5.0-rc.1 10.3.0-rc.1 5.5.0-rc.2 10.3.0-rc.2 5.5.1 10.3.1 5.5.2 10.3.2 5.5.3 10.3.3 5.5.4 10.3.4 5.5.5 10.3.5 5.6.0 10.3.6 5.6.0-beta.1 10.3.7 5.6.0-rc.1 10.3.8 5.6.0-rc.2 10.4.0 5.6.1 10.4.0-beta.1 5.6.2 10.4.0-beta.2 5.6.3 10.4.0-rc.1 5.7.0 10.4.1 5.7.0-beta.1 10.4.2 5.7.0-rc.1 10.4.3 5.7.1 10.4.4 5.7.2 10.5.0 5.7.3 10.5.0-beta.1 5.8.0 10.5.0-beta.2 5.8.0-beta.1 10.5.0-rc.1 5.8.0-beta.2 10.5.0-rc.2 5.8.0-rc.1 10.5.0-rc.3 5.8.1 10.5.1 5.8.2 10.5.2 5.9.0 10.5.3 5.9.0-beta.1 10.6.0 5.9.0-rc.1 10.6.0-beta.1 5.9.0-rc.2 10.6.0-beta.2 5.9.1 10.6.0-rc.1 5.9.2 10.6.1 6.0.0 10.6.2 6.0.0-beta.1 10.7.0 6.0.0-rc.1 10.7.0-beta.1 6.0.1 10.7.0-beta.2 6.0.2 10.7.0-rc.1 6.1.0 3.0.0 6.1.0-beta.1 3.0.1 6.1.0-rc.1 3.0.2 6.1.0-rc.2 3.0.3 6.1.1 3.0.4 6.1.2 3.0.5 6.1.3 3.0.6 6.2.0 3.0.7 6.2.0-beta.1 3.0.8 6.2.0-rc.1 3.0.9 6.2.0-rc.2 3.1.0 6.2.1 3.1.1 6.2.2 3.1.2 6.2.3 3.2.0 6.3.0 3.2.1 6.3.0-beta.1 3.2.2 6.3.0-rc.1 3.2.3 6.3.0-rc.2 3.2.4 6.3.1 3.2.5 6.3.2 3.2.6 6.4.0 3.3.0 6.4.0-beta.1 3.3.1 6.4.0-rc.1 3.3.2 6.4.1 3.3.2-rc.1 6.4.2 3.3.3 6.5.0 3.3.4 6.5.0-beta.1 3.3.5 6.5.0-rc.1 3.3.6 6.5.0-rc.2 3.4.0 6.5.1 3.4.0-beta.1 6.5.2 3.4.0-rc.2 6.6.0 3.4.1 6.6.0-beta.1 3.4.2 6.6.0-rc.1 3.4.3 6.6.0-rc.2 3.4.4 6.6.1 3.4.5 6.6.2 3.4.6 6.7.0 3.4.7 6.7.0-beta.1 3.4.8 6.7.0-beta.2 3.5.0 6.7.0-rc.1 3.5.0-beta.1 6.7.1 3.5.0-rc.1 6.8.0 3.5.0-rc.2 6.8.0-beta.1 3.5.1 6.8.0-beta.2 3.5.10 6.8.0-rc.1 3.5.2 6.8.1 3.5.3 6.8.2 3.5.4 6.8.3 3.5.5 6.9.0 3.5.6 6.9.0-beta.1 3.5.7 6.9.0-beta.2 3.5.8 6.9.0-rc.1 3.5.9 6.9.1 3.6.0 6.9.2 3.6.0-beta.1 6.9.3 3.6.0-rc.1 6.9.4 3.6.0-rc.2 6.9.5 3.6.0-rc.3 7.0.0 3.6.1 7.0.0-beta.1 3.6.2 7.0.0-beta.2 3.6.3 7.0.0-beta.3 3.6.4 7.0.0-rc.1 3.6.5 7.0.0-rc.2 3.6.6 7.0.1 3.6.7 7.0.2 3.7.0 7.1.0 3.7.0-beta.1 7.1.0-beta.1 3.7.0-rc.1 7.1.0-beta.2 3.7.0-rc.2 7.1.0-rc.1 3.7.1 7.1.0-rc.2 3.7.2 7.1.1
woocommerce / vendor / maxmind-db / reader / ext / maxminddb.c
woocommerce / vendor / maxmind-db / reader / ext Last commit date
tests 5 years ago config.m4 2 years ago config.w32 4 years ago maxminddb.c 10 months ago php_maxminddb.h 10 months ago
maxminddb.c
820 lines
1 /* MaxMind, Inc., licenses this file to you under the Apache License, Version
2 * 2.0 (the "License"); you may not use this file except in compliance with
3 * the License. You may obtain a copy of the License at
4 *
5 * http://www.apache.org/licenses/LICENSE-2.0
6 *
7 * Unless required by applicable law or agreed to in writing, software
8 * distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
9 * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
10 * License for the specific language governing permissions and limitations
11 * under the License.
12 */
13
14 #include "php_maxminddb.h"
15
16 #ifdef HAVE_CONFIG_H
17 #include "config.h"
18 #endif
19
20 #include <php.h>
21 #include <zend.h>
22
23 #include "Zend/zend_exceptions.h"
24 #include "Zend/zend_types.h"
25 #include "ext/spl/spl_exceptions.h"
26 #include "ext/standard/info.h"
27 #include <maxminddb.h>
28
29 #ifdef ZTS
30 #include <TSRM.h>
31 #endif
32
33 #define __STDC_FORMAT_MACROS
34 #include <inttypes.h>
35
36 #define PHP_MAXMINDDB_NS ZEND_NS_NAME("MaxMind", "Db")
37 #define PHP_MAXMINDDB_READER_NS ZEND_NS_NAME(PHP_MAXMINDDB_NS, "Reader")
38 #define PHP_MAXMINDDB_METADATA_NS \
39 ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata")
40 #define PHP_MAXMINDDB_READER_EX_NS \
41 ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException")
42
43 #define Z_MAXMINDDB_P(zv) php_maxminddb_fetch_object(Z_OBJ_P(zv))
44 typedef size_t strsize_t;
45 typedef zend_object free_obj_t;
46
47 /* For PHP 8 compatibility */
48 #if PHP_VERSION_ID < 80000
49
50 #define PROP_OBJ(zv) (zv)
51
52 #else
53
54 #define PROP_OBJ(zv) Z_OBJ_P(zv)
55
56 #define TSRMLS_C
57 #define TSRMLS_CC
58 #define TSRMLS_DC
59
60 /* End PHP 8 compatibility */
61 #endif
62
63 #ifndef ZEND_ACC_CTOR
64 #define ZEND_ACC_CTOR 0
65 #endif
66
67 /* IS_MIXED was added in 2020 */
68 #ifndef IS_MIXED
69 #define IS_MIXED IS_UNDEF
70 #endif
71
72 /* ZEND_THIS was added in 7.4 */
73 #ifndef ZEND_THIS
74 #define ZEND_THIS (&EX(This))
75 #endif
76
77 typedef struct _maxminddb_obj {
78 MMDB_s *mmdb;
79 zend_object std;
80 } maxminddb_obj;
81
82 PHP_FUNCTION(maxminddb);
83
84 static int
85 get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len);
86 static const MMDB_entry_data_list_s *
87 handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
88 zval *z_value TSRMLS_DC);
89 static const MMDB_entry_data_list_s *
90 handle_array(const MMDB_entry_data_list_s *entry_data_list,
91 zval *z_value TSRMLS_DC);
92 static const MMDB_entry_data_list_s *
93 handle_map(const MMDB_entry_data_list_s *entry_data_list,
94 zval *z_value TSRMLS_DC);
95 static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
96 zval *z_value TSRMLS_DC);
97 static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
98 zval *z_value TSRMLS_DC);
99 static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
100 zval *z_value TSRMLS_DC);
101
102 #define CHECK_ALLOCATED(val) \
103 if (!val) { \
104 zend_error(E_ERROR, "Out of memory"); \
105 return; \
106 }
107
108 static zend_object_handlers maxminddb_obj_handlers;
109 static zend_class_entry *maxminddb_ce, *maxminddb_exception_ce, *metadata_ce;
110
111 static inline maxminddb_obj *
112 php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) {
113 return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std));
114 }
115
116 ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_construct, 0, 0, 1)
117 ZEND_ARG_TYPE_INFO(0, db_file, IS_STRING, 0)
118 ZEND_END_ARG_INFO()
119
120 PHP_METHOD(MaxMind_Db_Reader, __construct) {
121 char *db_file = NULL;
122 strsize_t name_len;
123 zval *_this_zval = NULL;
124
125 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
126 getThis(),
127 "Os",
128 &_this_zval,
129 maxminddb_ce,
130 &db_file,
131 &name_len) == FAILURE) {
132 return;
133 }
134
135 if (0 != php_check_open_basedir(db_file TSRMLS_CC) ||
136 0 != access(db_file, R_OK)) {
137 zend_throw_exception_ex(
138 spl_ce_InvalidArgumentException,
139 0 TSRMLS_CC,
140 "The file \"%s\" does not exist or is not readable.",
141 db_file);
142 return;
143 }
144
145 MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s));
146 int const status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
147
148 if (MMDB_SUCCESS != status) {
149 zend_throw_exception_ex(
150 maxminddb_exception_ce,
151 0 TSRMLS_CC,
152 "Error opening database file (%s). Is this a valid "
153 "MaxMind DB file?",
154 db_file);
155 efree(mmdb);
156 return;
157 }
158
159 maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(ZEND_THIS);
160 mmdb_obj->mmdb = mmdb;
161 }
162
163 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
164 arginfo_maxminddbreader_get, 0, 1, IS_MIXED, 1)
165 ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
166 ZEND_END_ARG_INFO()
167
168 PHP_METHOD(MaxMind_Db_Reader, get) {
169 int prefix_len = 0;
170 get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len);
171 }
172
173 ZEND_BEGIN_ARG_WITH_RETURN_TYPE_INFO_EX(
174 arginfo_maxminddbreader_getWithPrefixLen, 0, 1, IS_ARRAY, 1)
175 ZEND_ARG_TYPE_INFO(0, ip_address, IS_STRING, 0)
176 ZEND_END_ARG_INFO()
177
178 PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) {
179 zval record, z_prefix_len;
180
181 int prefix_len = 0;
182 if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, &record, &prefix_len) ==
183 FAILURE) {
184 return;
185 }
186
187 array_init(return_value);
188 add_next_index_zval(return_value, &record);
189
190 ZVAL_LONG(&z_prefix_len, prefix_len);
191 add_next_index_zval(return_value, &z_prefix_len);
192 }
193
194 static int
195 get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len) {
196 char *ip_address = NULL;
197 strsize_t name_len;
198 zval *this_zval = NULL;
199
200 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
201 getThis(),
202 "Os",
203 &this_zval,
204 maxminddb_ce,
205 &ip_address,
206 &name_len) == FAILURE) {
207 return FAILURE;
208 }
209
210 const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(ZEND_THIS);
211
212 MMDB_s *mmdb = mmdb_obj->mmdb;
213
214 if (NULL == mmdb) {
215 zend_throw_exception_ex(spl_ce_BadMethodCallException,
216 0 TSRMLS_CC,
217 "Attempt to read from a closed MaxMind DB.");
218 return FAILURE;
219 }
220
221 struct addrinfo hints = {
222 .ai_family = AF_UNSPEC,
223 .ai_flags = AI_NUMERICHOST,
224 /* We set ai_socktype so that we only get one result back */
225 .ai_socktype = SOCK_STREAM};
226
227 struct addrinfo *addresses = NULL;
228 int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses);
229 if (gai_status) {
230 zend_throw_exception_ex(spl_ce_InvalidArgumentException,
231 0 TSRMLS_CC,
232 "The value \"%s\" is not a valid IP address.",
233 ip_address);
234 return FAILURE;
235 }
236 if (!addresses || !addresses->ai_addr) {
237 zend_throw_exception_ex(
238 spl_ce_InvalidArgumentException,
239 0 TSRMLS_CC,
240 "getaddrinfo was successful but failed to set the addrinfo");
241 return FAILURE;
242 }
243
244 int sa_family = addresses->ai_addr->sa_family;
245
246 int mmdb_error = MMDB_SUCCESS;
247 MMDB_lookup_result_s result =
248 MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
249
250 freeaddrinfo(addresses);
251
252 if (MMDB_SUCCESS != mmdb_error) {
253 zend_class_entry *ex;
254 if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
255 ex = spl_ce_InvalidArgumentException;
256 } else {
257 ex = maxminddb_exception_ce;
258 }
259 zend_throw_exception_ex(ex,
260 0 TSRMLS_CC,
261 "Error looking up %s. %s",
262 ip_address,
263 MMDB_strerror(mmdb_error));
264 return FAILURE;
265 }
266
267 *prefix_len = result.netmask;
268
269 if (sa_family == AF_INET && mmdb->metadata.ip_version == 6) {
270 /* We return the prefix length given the IPv4 address. If there is
271 no IPv4 subtree, we return a prefix length of 0. */
272 *prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0;
273 }
274
275 if (!result.found_entry) {
276 ZVAL_NULL(record);
277 return SUCCESS;
278 }
279
280 MMDB_entry_data_list_s *entry_data_list = NULL;
281 int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
282
283 if (MMDB_SUCCESS != status) {
284 zend_throw_exception_ex(maxminddb_exception_ce,
285 0 TSRMLS_CC,
286 "Error while looking up data for %s. %s",
287 ip_address,
288 MMDB_strerror(status));
289 MMDB_free_entry_data_list(entry_data_list);
290 return FAILURE;
291 } else if (NULL == entry_data_list) {
292 zend_throw_exception_ex(
293 maxminddb_exception_ce,
294 0 TSRMLS_CC,
295 "Error while looking up data for %s. Your database may "
296 "be corrupt or you have found a bug in libmaxminddb.",
297 ip_address);
298 return FAILURE;
299 }
300
301 const MMDB_entry_data_list_s *rv =
302 handle_entry_data_list(entry_data_list, record TSRMLS_CC);
303 if (rv == NULL) {
304 /* We should have already thrown the exception in handle_entry_data_list
305 */
306 return FAILURE;
307 }
308 MMDB_free_entry_data_list(entry_data_list);
309 return SUCCESS;
310 }
311
312 ZEND_BEGIN_ARG_INFO_EX(arginfo_maxminddbreader_void, 0, 0, 0)
313 ZEND_END_ARG_INFO()
314
315 PHP_METHOD(MaxMind_Db_Reader, metadata) {
316 zval *this_zval = NULL;
317
318 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
319 getThis(),
320 "O",
321 &this_zval,
322 maxminddb_ce) == FAILURE) {
323 return;
324 }
325
326 const maxminddb_obj *const mmdb_obj =
327 (maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
328
329 if (NULL == mmdb_obj->mmdb) {
330 zend_throw_exception_ex(spl_ce_BadMethodCallException,
331 0 TSRMLS_CC,
332 "Attempt to read from a closed MaxMind DB.");
333 return;
334 }
335
336 object_init_ex(return_value, metadata_ce);
337
338 MMDB_entry_data_list_s *entry_data_list;
339 int status =
340 MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
341 if (status != MMDB_SUCCESS) {
342 zend_throw_exception_ex(maxminddb_exception_ce,
343 0 TSRMLS_CC,
344 "Error while decoding metadata. %s",
345 MMDB_strerror(status));
346 return;
347 }
348
349 zval metadata_array;
350 const MMDB_entry_data_list_s *rv =
351 handle_entry_data_list(entry_data_list, &metadata_array TSRMLS_CC);
352 if (rv == NULL) {
353 return;
354 }
355 MMDB_free_entry_data_list(entry_data_list);
356 zend_call_method_with_1_params(PROP_OBJ(return_value),
357 metadata_ce,
358 &metadata_ce->constructor,
359 ZEND_CONSTRUCTOR_FUNC_NAME,
360 NULL,
361 &metadata_array);
362 zval_ptr_dtor(&metadata_array);
363 }
364
365 PHP_METHOD(MaxMind_Db_Reader, close) {
366 zval *this_zval = NULL;
367
368 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
369 getThis(),
370 "O",
371 &this_zval,
372 maxminddb_ce) == FAILURE) {
373 return;
374 }
375
376 maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
377
378 if (NULL == mmdb_obj->mmdb) {
379 zend_throw_exception_ex(spl_ce_BadMethodCallException,
380 0 TSRMLS_CC,
381 "Attempt to close a closed MaxMind DB.");
382 return;
383 }
384 MMDB_close(mmdb_obj->mmdb);
385 efree(mmdb_obj->mmdb);
386 mmdb_obj->mmdb = NULL;
387 }
388
389 static const MMDB_entry_data_list_s *
390 handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
391 zval *z_value TSRMLS_DC) {
392 switch (entry_data_list->entry_data.type) {
393 case MMDB_DATA_TYPE_MAP:
394 return handle_map(entry_data_list, z_value TSRMLS_CC);
395 case MMDB_DATA_TYPE_ARRAY:
396 return handle_array(entry_data_list, z_value TSRMLS_CC);
397 case MMDB_DATA_TYPE_UTF8_STRING:
398 ZVAL_STRINGL(z_value,
399 entry_data_list->entry_data.utf8_string,
400 entry_data_list->entry_data.data_size);
401 break;
402 case MMDB_DATA_TYPE_BYTES:
403 ZVAL_STRINGL(z_value,
404 (char const *)entry_data_list->entry_data.bytes,
405 entry_data_list->entry_data.data_size);
406 break;
407 case MMDB_DATA_TYPE_DOUBLE:
408 ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value);
409 break;
410 case MMDB_DATA_TYPE_FLOAT:
411 ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value);
412 break;
413 case MMDB_DATA_TYPE_UINT16:
414 ZVAL_LONG(z_value, entry_data_list->entry_data.uint16);
415 break;
416 case MMDB_DATA_TYPE_UINT32:
417 handle_uint32(entry_data_list, z_value TSRMLS_CC);
418 break;
419 case MMDB_DATA_TYPE_BOOLEAN:
420 ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean);
421 break;
422 case MMDB_DATA_TYPE_UINT64:
423 handle_uint64(entry_data_list, z_value TSRMLS_CC);
424 break;
425 case MMDB_DATA_TYPE_UINT128:
426 handle_uint128(entry_data_list, z_value TSRMLS_CC);
427 break;
428 case MMDB_DATA_TYPE_INT32:
429 ZVAL_LONG(z_value, entry_data_list->entry_data.int32);
430 break;
431 default:
432 zend_throw_exception_ex(maxminddb_exception_ce,
433 0 TSRMLS_CC,
434 "Invalid data type arguments: %d",
435 entry_data_list->entry_data.type);
436 return NULL;
437 }
438 return entry_data_list;
439 }
440
441 static const MMDB_entry_data_list_s *
442 handle_map(const MMDB_entry_data_list_s *entry_data_list,
443 zval *z_value TSRMLS_DC) {
444 array_init(z_value);
445 const uint32_t map_size = entry_data_list->entry_data.data_size;
446
447 uint32_t i;
448 for (i = 0; i < map_size && entry_data_list; i++) {
449 entry_data_list = entry_data_list->next;
450
451 char *key = estrndup(entry_data_list->entry_data.utf8_string,
452 entry_data_list->entry_data.data_size);
453 if (NULL == key) {
454 zend_throw_exception_ex(maxminddb_exception_ce,
455 0 TSRMLS_CC,
456 "Invalid data type arguments");
457 return NULL;
458 }
459
460 entry_data_list = entry_data_list->next;
461 zval new_value;
462 entry_data_list =
463 handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
464 if (entry_data_list != NULL) {
465 add_assoc_zval(z_value, key, &new_value);
466 }
467 efree(key);
468 }
469 return entry_data_list;
470 }
471
472 static const MMDB_entry_data_list_s *
473 handle_array(const MMDB_entry_data_list_s *entry_data_list,
474 zval *z_value TSRMLS_DC) {
475 const uint32_t size = entry_data_list->entry_data.data_size;
476
477 array_init(z_value);
478
479 uint32_t i;
480 for (i = 0; i < size && entry_data_list; i++) {
481 entry_data_list = entry_data_list->next;
482 zval new_value;
483 entry_data_list =
484 handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
485 if (entry_data_list != NULL) {
486 add_next_index_zval(z_value, &new_value);
487 }
488 }
489 return entry_data_list;
490 }
491
492 static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
493 zval *z_value TSRMLS_DC) {
494 uint64_t high = 0;
495 uint64_t low = 0;
496 #if MMDB_UINT128_IS_BYTE_ARRAY
497 int i;
498 for (i = 0; i < 8; i++) {
499 high = (high << 8) | entry_data_list->entry_data.uint128[i];
500 }
501
502 for (i = 8; i < 16; i++) {
503 low = (low << 8) | entry_data_list->entry_data.uint128[i];
504 }
505 #else
506 high = entry_data_list->entry_data.uint128 >> 64;
507 low = (uint64_t)entry_data_list->entry_data.uint128;
508 #endif
509
510 char *num_str;
511 spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low);
512 CHECK_ALLOCATED(num_str);
513
514 ZVAL_STRING(z_value, num_str);
515 efree(num_str);
516 }
517
518 static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
519 zval *z_value TSRMLS_DC) {
520 uint32_t val = entry_data_list->entry_data.uint32;
521
522 #if LONG_MAX >= UINT32_MAX
523 ZVAL_LONG(z_value, val);
524 return;
525 #else
526 if (val <= LONG_MAX) {
527 ZVAL_LONG(z_value, val);
528 return;
529 }
530
531 char *int_str;
532 spprintf(&int_str, 0, "%" PRIu32, val);
533 CHECK_ALLOCATED(int_str);
534
535 ZVAL_STRING(z_value, int_str);
536 efree(int_str);
537 #endif
538 }
539
540 static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
541 zval *z_value TSRMLS_DC) {
542 uint64_t val = entry_data_list->entry_data.uint64;
543
544 #if LONG_MAX >= UINT64_MAX
545 ZVAL_LONG(z_value, val);
546 return;
547 #else
548 if (val <= LONG_MAX) {
549 ZVAL_LONG(z_value, val);
550 return;
551 }
552
553 char *int_str;
554 spprintf(&int_str, 0, "%" PRIu64, val);
555 CHECK_ALLOCATED(int_str);
556
557 ZVAL_STRING(z_value, int_str);
558 efree(int_str);
559 #endif
560 }
561
562 static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) {
563 maxminddb_obj *obj =
564 php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC);
565 if (obj->mmdb != NULL) {
566 MMDB_close(obj->mmdb);
567 efree(obj->mmdb);
568 }
569
570 zend_object_std_dtor(&obj->std TSRMLS_CC);
571 }
572
573 static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
574 maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));
575 zend_object_std_init(&obj->std, type TSRMLS_CC);
576 object_properties_init(&(obj->std), type);
577
578 obj->std.handlers = &maxminddb_obj_handlers;
579
580 return &obj->std;
581 }
582
583 /* clang-format off */
584 static zend_function_entry maxminddb_methods[] = {
585 PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxminddbreader_construct,
586 ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
587 PHP_ME(MaxMind_Db_Reader, close, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
588 PHP_ME(MaxMind_Db_Reader, get, arginfo_maxminddbreader_get, ZEND_ACC_PUBLIC)
589 PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxminddbreader_getWithPrefixLen, ZEND_ACC_PUBLIC)
590 PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
591 { NULL, NULL, NULL }
592 };
593 /* clang-format on */
594
595 ZEND_BEGIN_ARG_INFO_EX(arginfo_metadata_construct, 0, 0, 1)
596 ZEND_ARG_TYPE_INFO(0, metadata, IS_ARRAY, 0)
597 ZEND_END_ARG_INFO()
598
599 PHP_METHOD(MaxMind_Db_Reader_Metadata, __construct) {
600 zval *object = NULL;
601 zval *metadata_array = NULL;
602 zend_long node_count = 0;
603 zend_long record_size = 0;
604
605 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
606 getThis(),
607 "Oa",
608 &object,
609 metadata_ce,
610 &metadata_array) == FAILURE) {
611 return;
612 }
613
614 zval *tmp = NULL;
615 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
616 "binary_format_major_version",
617 sizeof("binary_format_major_version") - 1))) {
618 zend_update_property(metadata_ce,
619 PROP_OBJ(object),
620 "binaryFormatMajorVersion",
621 sizeof("binaryFormatMajorVersion") - 1,
622 tmp);
623 }
624
625 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
626 "binary_format_minor_version",
627 sizeof("binary_format_minor_version") - 1))) {
628 zend_update_property(metadata_ce,
629 PROP_OBJ(object),
630 "binaryFormatMinorVersion",
631 sizeof("binaryFormatMinorVersion") - 1,
632 tmp);
633 }
634
635 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
636 "build_epoch",
637 sizeof("build_epoch") - 1))) {
638 zend_update_property(metadata_ce,
639 PROP_OBJ(object),
640 "buildEpoch",
641 sizeof("buildEpoch") - 1,
642 tmp);
643 }
644
645 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
646 "database_type",
647 sizeof("database_type") - 1))) {
648 zend_update_property(metadata_ce,
649 PROP_OBJ(object),
650 "databaseType",
651 sizeof("databaseType") - 1,
652 tmp);
653 }
654
655 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
656 "description",
657 sizeof("description") - 1))) {
658 zend_update_property(metadata_ce,
659 PROP_OBJ(object),
660 "description",
661 sizeof("description") - 1,
662 tmp);
663 }
664
665 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
666 "ip_version",
667 sizeof("ip_version") - 1))) {
668 zend_update_property(metadata_ce,
669 PROP_OBJ(object),
670 "ipVersion",
671 sizeof("ipVersion") - 1,
672 tmp);
673 }
674
675 if ((tmp = zend_hash_str_find(
676 HASH_OF(metadata_array), "languages", sizeof("languages") - 1))) {
677 zend_update_property(metadata_ce,
678 PROP_OBJ(object),
679 "languages",
680 sizeof("languages") - 1,
681 tmp);
682 }
683
684 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
685 "record_size",
686 sizeof("record_size") - 1))) {
687 zend_update_property(metadata_ce,
688 PROP_OBJ(object),
689 "recordSize",
690 sizeof("recordSize") - 1,
691 tmp);
692 if (Z_TYPE_P(tmp) == IS_LONG) {
693 record_size = Z_LVAL_P(tmp);
694 }
695 }
696
697 if (record_size != 0) {
698 zend_update_property_long(metadata_ce,
699 PROP_OBJ(object),
700 "nodeByteSize",
701 sizeof("nodeByteSize") - 1,
702 record_size / 4);
703 }
704
705 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
706 "node_count",
707 sizeof("node_count") - 1))) {
708 zend_update_property(metadata_ce,
709 PROP_OBJ(object),
710 "nodeCount",
711 sizeof("nodeCount") - 1,
712 tmp);
713 if (Z_TYPE_P(tmp) == IS_LONG) {
714 node_count = Z_LVAL_P(tmp);
715 }
716 }
717
718 if (record_size != 0) {
719 zend_update_property_long(metadata_ce,
720 PROP_OBJ(object),
721 "searchTreeSize",
722 sizeof("searchTreeSize") - 1,
723 record_size * node_count / 4);
724 }
725 }
726
727 // clang-format off
728 static zend_function_entry metadata_methods[] = {
729 PHP_ME(MaxMind_Db_Reader_Metadata, __construct, arginfo_metadata_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
730 {NULL, NULL, NULL}
731 };
732 // clang-format on
733
734 PHP_MINIT_FUNCTION(maxminddb) {
735 zend_class_entry ce;
736
737 INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_EX_NS, NULL);
738 maxminddb_exception_ce =
739 zend_register_internal_class_ex(&ce, zend_ce_exception);
740
741 INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods);
742 maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC);
743 maxminddb_ce->create_object = maxminddb_create_handler;
744
745 INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_METADATA_NS, metadata_methods);
746 metadata_ce = zend_register_internal_class(&ce TSRMLS_CC);
747 zend_declare_property_null(metadata_ce,
748 "binaryFormatMajorVersion",
749 sizeof("binaryFormatMajorVersion") - 1,
750 ZEND_ACC_PUBLIC);
751 zend_declare_property_null(metadata_ce,
752 "binaryFormatMinorVersion",
753 sizeof("binaryFormatMinorVersion") - 1,
754 ZEND_ACC_PUBLIC);
755 zend_declare_property_null(
756 metadata_ce, "buildEpoch", sizeof("buildEpoch") - 1, ZEND_ACC_PUBLIC);
757 zend_declare_property_null(metadata_ce,
758 "databaseType",
759 sizeof("databaseType") - 1,
760 ZEND_ACC_PUBLIC);
761 zend_declare_property_null(
762 metadata_ce, "description", sizeof("description") - 1, ZEND_ACC_PUBLIC);
763 zend_declare_property_null(
764 metadata_ce, "ipVersion", sizeof("ipVersion") - 1, ZEND_ACC_PUBLIC);
765 zend_declare_property_null(
766 metadata_ce, "languages", sizeof("languages") - 1, ZEND_ACC_PUBLIC);
767 zend_declare_property_null(metadata_ce,
768 "nodeByteSize",
769 sizeof("nodeByteSize") - 1,
770 ZEND_ACC_PUBLIC);
771 zend_declare_property_null(
772 metadata_ce, "nodeCount", sizeof("nodeCount") - 1, ZEND_ACC_PUBLIC);
773 zend_declare_property_null(
774 metadata_ce, "recordSize", sizeof("recordSize") - 1, ZEND_ACC_PUBLIC);
775 zend_declare_property_null(metadata_ce,
776 "searchTreeSize",
777 sizeof("searchTreeSize") - 1,
778 ZEND_ACC_PUBLIC);
779
780 memcpy(&maxminddb_obj_handlers,
781 zend_get_std_object_handlers(),
782 sizeof(zend_object_handlers));
783 maxminddb_obj_handlers.clone_obj = NULL;
784 maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
785 maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
786 zend_declare_class_constant_string(maxminddb_ce,
787 "MMDB_LIB_VERSION",
788 sizeof("MMDB_LIB_VERSION") - 1,
789 MMDB_lib_version() TSRMLS_CC);
790
791 return SUCCESS;
792 }
793
794 static PHP_MINFO_FUNCTION(maxminddb) {
795 php_info_print_table_start();
796
797 php_info_print_table_row(2, "MaxMind DB Reader", "enabled");
798 php_info_print_table_row(
799 2, "maxminddb extension version", PHP_MAXMINDDB_VERSION);
800 php_info_print_table_row(
801 2, "libmaxminddb library version", MMDB_lib_version());
802
803 php_info_print_table_end();
804 }
805
806 zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER,
807 PHP_MAXMINDDB_EXTNAME,
808 NULL,
809 PHP_MINIT(maxminddb),
810 NULL,
811 NULL,
812 NULL,
813 PHP_MINFO(maxminddb),
814 PHP_MAXMINDDB_VERSION,
815 STANDARD_MODULE_PROPERTIES};
816
817 #ifdef COMPILE_DL_MAXMINDDB
818 ZEND_GET_MODULE(maxminddb)
819 #endif
820