PluginProbe ʕ •ᴥ•ʔ
Independent Analytics – WordPress Analytics Plugin / 2.3.1
Independent Analytics – WordPress Analytics Plugin v2.3.1
2.15.3 2.15.2 2.15.1 2.15.0 2.14.10 trunk 1.1 1.10 1.10.1 1.11 1.12 1.13 1.14 1.15 1.16 1.17 1.17.1 1.17.2 1.17.3 1.17.4 1.18 1.18.1 1.19.0 1.19.1 1.2 1.20.0 1.21.0 1.22.0 1.22.1 1.23.0 1.23.1 1.24.0 1.24.1 1.25.0 1.25.1 1.26.0 1.27.0 1.28.0 1.28.1 1.28.2 1.28.3 1.29.0 1.3 1.30.0 1.30.1 1.4 1.5 1.6 1.7 1.8 1.9 2.0.0 2.0.1 2.1.4 2.1.5 2.1.6 2.10.0 2.10.1 2.10.2 2.10.3 2.10.4 2.11.0 2.11.1 2.11.10 2.11.2 2.11.3 2.11.4 2.11.5 2.11.6 2.11.7 2.11.8 2.11.9 2.12.0 2.12.1 2.12.2 2.13.1 2.13.2 2.13.5 2.13.6 2.14.0 2.14.1 2.14.2 2.14.4 2.14.6 2.14.7 2.14.8 2.14.9 2.2.0 2.2.1 2.3.1 2.3.2 2.4.2 2.4.3 2.5.0 2.5.1 2.6.0 2.6.1 2.6.2 2.6.3 2.6.4 2.7.0 2.7.1 2.7.2 2.7.3 2.8.2 2.8.3 2.8.4 2.8.5 2.8.6 2.8.7 2.8.8 2.8.9 2.9.2 2.9.3 2.9.4 2.9.5 2.9.6 2.9.7
independent-analytics / vendor / maxmind-db / reader / ext / maxminddb.c
independent-analytics / vendor / maxmind-db / reader / ext Last commit date
config.m4 2 years ago config.w32 3 years ago maxminddb.c 2 years ago php_maxminddb.h 2 years ago
maxminddb.c
812 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 MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
340
341 zval metadata_array;
342 const MMDB_entry_data_list_s *rv =
343 handle_entry_data_list(entry_data_list, &metadata_array TSRMLS_CC);
344 if (rv == NULL) {
345 return;
346 }
347 MMDB_free_entry_data_list(entry_data_list);
348 zend_call_method_with_1_params(PROP_OBJ(return_value),
349 metadata_ce,
350 &metadata_ce->constructor,
351 ZEND_CONSTRUCTOR_FUNC_NAME,
352 NULL,
353 &metadata_array);
354 zval_ptr_dtor(&metadata_array);
355 }
356
357 PHP_METHOD(MaxMind_Db_Reader, close) {
358 zval *this_zval = NULL;
359
360 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
361 getThis(),
362 "O",
363 &this_zval,
364 maxminddb_ce) == FAILURE) {
365 return;
366 }
367
368 maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(this_zval);
369
370 if (NULL == mmdb_obj->mmdb) {
371 zend_throw_exception_ex(spl_ce_BadMethodCallException,
372 0 TSRMLS_CC,
373 "Attempt to close a closed MaxMind DB.");
374 return;
375 }
376 MMDB_close(mmdb_obj->mmdb);
377 efree(mmdb_obj->mmdb);
378 mmdb_obj->mmdb = NULL;
379 }
380
381 static const MMDB_entry_data_list_s *
382 handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
383 zval *z_value TSRMLS_DC) {
384 switch (entry_data_list->entry_data.type) {
385 case MMDB_DATA_TYPE_MAP:
386 return handle_map(entry_data_list, z_value TSRMLS_CC);
387 case MMDB_DATA_TYPE_ARRAY:
388 return handle_array(entry_data_list, z_value TSRMLS_CC);
389 case MMDB_DATA_TYPE_UTF8_STRING:
390 ZVAL_STRINGL(z_value,
391 entry_data_list->entry_data.utf8_string,
392 entry_data_list->entry_data.data_size);
393 break;
394 case MMDB_DATA_TYPE_BYTES:
395 ZVAL_STRINGL(z_value,
396 (char const *)entry_data_list->entry_data.bytes,
397 entry_data_list->entry_data.data_size);
398 break;
399 case MMDB_DATA_TYPE_DOUBLE:
400 ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value);
401 break;
402 case MMDB_DATA_TYPE_FLOAT:
403 ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value);
404 break;
405 case MMDB_DATA_TYPE_UINT16:
406 ZVAL_LONG(z_value, entry_data_list->entry_data.uint16);
407 break;
408 case MMDB_DATA_TYPE_UINT32:
409 handle_uint32(entry_data_list, z_value TSRMLS_CC);
410 break;
411 case MMDB_DATA_TYPE_BOOLEAN:
412 ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean);
413 break;
414 case MMDB_DATA_TYPE_UINT64:
415 handle_uint64(entry_data_list, z_value TSRMLS_CC);
416 break;
417 case MMDB_DATA_TYPE_UINT128:
418 handle_uint128(entry_data_list, z_value TSRMLS_CC);
419 break;
420 case MMDB_DATA_TYPE_INT32:
421 ZVAL_LONG(z_value, entry_data_list->entry_data.int32);
422 break;
423 default:
424 zend_throw_exception_ex(maxminddb_exception_ce,
425 0 TSRMLS_CC,
426 "Invalid data type arguments: %d",
427 entry_data_list->entry_data.type);
428 return NULL;
429 }
430 return entry_data_list;
431 }
432
433 static const MMDB_entry_data_list_s *
434 handle_map(const MMDB_entry_data_list_s *entry_data_list,
435 zval *z_value TSRMLS_DC) {
436 array_init(z_value);
437 const uint32_t map_size = entry_data_list->entry_data.data_size;
438
439 uint32_t i;
440 for (i = 0; i < map_size && entry_data_list; i++) {
441 entry_data_list = entry_data_list->next;
442
443 char *key = estrndup(entry_data_list->entry_data.utf8_string,
444 entry_data_list->entry_data.data_size);
445 if (NULL == key) {
446 zend_throw_exception_ex(maxminddb_exception_ce,
447 0 TSRMLS_CC,
448 "Invalid data type arguments");
449 return NULL;
450 }
451
452 entry_data_list = entry_data_list->next;
453 zval new_value;
454 entry_data_list =
455 handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
456 if (entry_data_list != NULL) {
457 add_assoc_zval(z_value, key, &new_value);
458 }
459 efree(key);
460 }
461 return entry_data_list;
462 }
463
464 static const MMDB_entry_data_list_s *
465 handle_array(const MMDB_entry_data_list_s *entry_data_list,
466 zval *z_value TSRMLS_DC) {
467 const uint32_t size = entry_data_list->entry_data.data_size;
468
469 array_init(z_value);
470
471 uint32_t i;
472 for (i = 0; i < size && entry_data_list; i++) {
473 entry_data_list = entry_data_list->next;
474 zval new_value;
475 entry_data_list =
476 handle_entry_data_list(entry_data_list, &new_value TSRMLS_CC);
477 if (entry_data_list != NULL) {
478 add_next_index_zval(z_value, &new_value);
479 }
480 }
481 return entry_data_list;
482 }
483
484 static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
485 zval *z_value TSRMLS_DC) {
486 uint64_t high = 0;
487 uint64_t low = 0;
488 #if MMDB_UINT128_IS_BYTE_ARRAY
489 int i;
490 for (i = 0; i < 8; i++) {
491 high = (high << 8) | entry_data_list->entry_data.uint128[i];
492 }
493
494 for (i = 8; i < 16; i++) {
495 low = (low << 8) | entry_data_list->entry_data.uint128[i];
496 }
497 #else
498 high = entry_data_list->entry_data.uint128 >> 64;
499 low = (uint64_t)entry_data_list->entry_data.uint128;
500 #endif
501
502 char *num_str;
503 spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low);
504 CHECK_ALLOCATED(num_str);
505
506 ZVAL_STRING(z_value, num_str);
507 efree(num_str);
508 }
509
510 static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
511 zval *z_value TSRMLS_DC) {
512 uint32_t val = entry_data_list->entry_data.uint32;
513
514 #if LONG_MAX >= UINT32_MAX
515 ZVAL_LONG(z_value, val);
516 return;
517 #else
518 if (val <= LONG_MAX) {
519 ZVAL_LONG(z_value, val);
520 return;
521 }
522
523 char *int_str;
524 spprintf(&int_str, 0, "%" PRIu32, val);
525 CHECK_ALLOCATED(int_str);
526
527 ZVAL_STRING(z_value, int_str);
528 efree(int_str);
529 #endif
530 }
531
532 static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
533 zval *z_value TSRMLS_DC) {
534 uint64_t val = entry_data_list->entry_data.uint64;
535
536 #if LONG_MAX >= UINT64_MAX
537 ZVAL_LONG(z_value, val);
538 return;
539 #else
540 if (val <= LONG_MAX) {
541 ZVAL_LONG(z_value, val);
542 return;
543 }
544
545 char *int_str;
546 spprintf(&int_str, 0, "%" PRIu64, val);
547 CHECK_ALLOCATED(int_str);
548
549 ZVAL_STRING(z_value, int_str);
550 efree(int_str);
551 #endif
552 }
553
554 static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) {
555 maxminddb_obj *obj =
556 php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC);
557 if (obj->mmdb != NULL) {
558 MMDB_close(obj->mmdb);
559 efree(obj->mmdb);
560 }
561
562 zend_object_std_dtor(&obj->std TSRMLS_CC);
563 }
564
565 static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
566 maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));
567 zend_object_std_init(&obj->std, type TSRMLS_CC);
568 object_properties_init(&(obj->std), type);
569
570 obj->std.handlers = &maxminddb_obj_handlers;
571
572 return &obj->std;
573 }
574
575 /* clang-format off */
576 static zend_function_entry maxminddb_methods[] = {
577 PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxminddbreader_construct,
578 ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
579 PHP_ME(MaxMind_Db_Reader, close, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
580 PHP_ME(MaxMind_Db_Reader, get, arginfo_maxminddbreader_get, ZEND_ACC_PUBLIC)
581 PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxminddbreader_getWithPrefixLen, ZEND_ACC_PUBLIC)
582 PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxminddbreader_void, ZEND_ACC_PUBLIC)
583 { NULL, NULL, NULL }
584 };
585 /* clang-format on */
586
587 ZEND_BEGIN_ARG_INFO_EX(arginfo_metadata_construct, 0, 0, 1)
588 ZEND_ARG_TYPE_INFO(0, metadata, IS_ARRAY, 0)
589 ZEND_END_ARG_INFO()
590
591 PHP_METHOD(MaxMind_Db_Reader_Metadata, __construct) {
592 zval *object = NULL;
593 zval *metadata_array = NULL;
594 zend_long node_count = 0;
595 zend_long record_size = 0;
596
597 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
598 getThis(),
599 "Oa",
600 &object,
601 metadata_ce,
602 &metadata_array) == FAILURE) {
603 return;
604 }
605
606 zval *tmp = NULL;
607 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
608 "binary_format_major_version",
609 sizeof("binary_format_major_version") - 1))) {
610 zend_update_property(metadata_ce,
611 PROP_OBJ(object),
612 "binaryFormatMajorVersion",
613 sizeof("binaryFormatMajorVersion") - 1,
614 tmp);
615 }
616
617 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
618 "binary_format_minor_version",
619 sizeof("binary_format_minor_version") - 1))) {
620 zend_update_property(metadata_ce,
621 PROP_OBJ(object),
622 "binaryFormatMinorVersion",
623 sizeof("binaryFormatMinorVersion") - 1,
624 tmp);
625 }
626
627 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
628 "build_epoch",
629 sizeof("build_epoch") - 1))) {
630 zend_update_property(metadata_ce,
631 PROP_OBJ(object),
632 "buildEpoch",
633 sizeof("buildEpoch") - 1,
634 tmp);
635 }
636
637 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
638 "database_type",
639 sizeof("database_type") - 1))) {
640 zend_update_property(metadata_ce,
641 PROP_OBJ(object),
642 "databaseType",
643 sizeof("databaseType") - 1,
644 tmp);
645 }
646
647 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
648 "description",
649 sizeof("description") - 1))) {
650 zend_update_property(metadata_ce,
651 PROP_OBJ(object),
652 "description",
653 sizeof("description") - 1,
654 tmp);
655 }
656
657 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
658 "ip_version",
659 sizeof("ip_version") - 1))) {
660 zend_update_property(metadata_ce,
661 PROP_OBJ(object),
662 "ipVersion",
663 sizeof("ipVersion") - 1,
664 tmp);
665 }
666
667 if ((tmp = zend_hash_str_find(
668 HASH_OF(metadata_array), "languages", sizeof("languages") - 1))) {
669 zend_update_property(metadata_ce,
670 PROP_OBJ(object),
671 "languages",
672 sizeof("languages") - 1,
673 tmp);
674 }
675
676 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
677 "record_size",
678 sizeof("record_size") - 1))) {
679 zend_update_property(metadata_ce,
680 PROP_OBJ(object),
681 "recordSize",
682 sizeof("recordSize") - 1,
683 tmp);
684 if (Z_TYPE_P(tmp) == IS_LONG) {
685 record_size = Z_LVAL_P(tmp);
686 }
687 }
688
689 if (record_size != 0) {
690 zend_update_property_long(metadata_ce,
691 PROP_OBJ(object),
692 "nodeByteSize",
693 sizeof("nodeByteSize") - 1,
694 record_size / 4);
695 }
696
697 if ((tmp = zend_hash_str_find(HASH_OF(metadata_array),
698 "node_count",
699 sizeof("node_count") - 1))) {
700 zend_update_property(metadata_ce,
701 PROP_OBJ(object),
702 "nodeCount",
703 sizeof("nodeCount") - 1,
704 tmp);
705 if (Z_TYPE_P(tmp) == IS_LONG) {
706 node_count = Z_LVAL_P(tmp);
707 }
708 }
709
710 if (record_size != 0) {
711 zend_update_property_long(metadata_ce,
712 PROP_OBJ(object),
713 "searchTreeSize",
714 sizeof("searchTreeSize") - 1,
715 record_size * node_count / 4);
716 }
717 }
718
719 // clang-format off
720 static zend_function_entry metadata_methods[] = {
721 PHP_ME(MaxMind_Db_Reader_Metadata, __construct, arginfo_metadata_construct, ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
722 {NULL, NULL, NULL}
723 };
724 // clang-format on
725
726 PHP_MINIT_FUNCTION(maxminddb) {
727 zend_class_entry ce;
728
729 INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_EX_NS, NULL);
730 maxminddb_exception_ce =
731 zend_register_internal_class_ex(&ce, zend_ce_exception);
732
733 INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods);
734 maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC);
735 maxminddb_ce->create_object = maxminddb_create_handler;
736
737 INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_METADATA_NS, metadata_methods);
738 metadata_ce = zend_register_internal_class(&ce TSRMLS_CC);
739 zend_declare_property_null(metadata_ce,
740 "binaryFormatMajorVersion",
741 sizeof("binaryFormatMajorVersion") - 1,
742 ZEND_ACC_PUBLIC);
743 zend_declare_property_null(metadata_ce,
744 "binaryFormatMinorVersion",
745 sizeof("binaryFormatMinorVersion") - 1,
746 ZEND_ACC_PUBLIC);
747 zend_declare_property_null(
748 metadata_ce, "buildEpoch", sizeof("buildEpoch") - 1, ZEND_ACC_PUBLIC);
749 zend_declare_property_null(metadata_ce,
750 "databaseType",
751 sizeof("databaseType") - 1,
752 ZEND_ACC_PUBLIC);
753 zend_declare_property_null(
754 metadata_ce, "description", sizeof("description") - 1, ZEND_ACC_PUBLIC);
755 zend_declare_property_null(
756 metadata_ce, "ipVersion", sizeof("ipVersion") - 1, ZEND_ACC_PUBLIC);
757 zend_declare_property_null(
758 metadata_ce, "languages", sizeof("languages") - 1, ZEND_ACC_PUBLIC);
759 zend_declare_property_null(metadata_ce,
760 "nodeByteSize",
761 sizeof("nodeByteSize") - 1,
762 ZEND_ACC_PUBLIC);
763 zend_declare_property_null(
764 metadata_ce, "nodeCount", sizeof("nodeCount") - 1, ZEND_ACC_PUBLIC);
765 zend_declare_property_null(
766 metadata_ce, "recordSize", sizeof("recordSize") - 1, ZEND_ACC_PUBLIC);
767 zend_declare_property_null(metadata_ce,
768 "searchTreeSize",
769 sizeof("searchTreeSize") - 1,
770 ZEND_ACC_PUBLIC);
771
772 memcpy(&maxminddb_obj_handlers,
773 zend_get_std_object_handlers(),
774 sizeof(zend_object_handlers));
775 maxminddb_obj_handlers.clone_obj = NULL;
776 maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
777 maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
778 zend_declare_class_constant_string(maxminddb_ce,
779 "MMDB_LIB_VERSION",
780 sizeof("MMDB_LIB_VERSION") - 1,
781 MMDB_lib_version() TSRMLS_CC);
782
783 return SUCCESS;
784 }
785
786 static PHP_MINFO_FUNCTION(maxminddb) {
787 php_info_print_table_start();
788
789 php_info_print_table_row(2, "MaxMind DB Reader", "enabled");
790 php_info_print_table_row(
791 2, "maxminddb extension version", PHP_MAXMINDDB_VERSION);
792 php_info_print_table_row(
793 2, "libmaxminddb library version", MMDB_lib_version());
794
795 php_info_print_table_end();
796 }
797
798 zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER,
799 PHP_MAXMINDDB_EXTNAME,
800 NULL,
801 PHP_MINIT(maxminddb),
802 NULL,
803 NULL,
804 NULL,
805 PHP_MINFO(maxminddb),
806 PHP_MAXMINDDB_VERSION,
807 STANDARD_MODULE_PROPERTIES};
808
809 #ifdef COMPILE_DL_MAXMINDDB
810 ZEND_GET_MODULE(maxminddb)
811 #endif
812