PluginProbe ʕ •ᴥ•ʔ
Matomo Analytics – Powerful, Privacy-First Insights for WordPress / 5.8.2
Matomo Analytics – Powerful, Privacy-First Insights for WordPress v5.8.2
5.11.1 5.11.0 5.10.2 5.10.1 trunk 1.0.2 1.0.3 1.0.4 1.0.5 1.0.6 1.1.0 1.1.1 1.1.2 1.1.3 1.2.0 1.3.0 1.3.1 1.3.2 4.0.0 4.0.1 4.0.2 4.0.3 4.0.4 4.1.0 4.1.1 4.1.2 4.1.3 4.10.0 4.11.0 4.12.0 4.13.0 4.13.2 4.13.3 4.13.4 4.13.5 4.14.0 4.14.1 4.14.2 4.15.0 4.15.1 4.15.2 4.15.3 4.2.0 4.3.0 4.3.1 4.4.1 4.4.2 4.5.0 4.6.0 5.0.1 5.0.2 5.0.3 5.0.4 5.0.5 5.0.6 5.0.7 5.0.8 5.1.0 5.1.1 5.1.2 5.1.3 5.1.4 5.1.5 5.1.6 5.1.7 5.10.0 5.2.0 5.2.1 5.2.2 5.3.0 5.3.1 5.3.2 5.3.3 5.6.0 5.6.1 5.7.0 5.7.1 5.8.0 5.8.1 5.8.2
matomo / app / vendor / prefixed / maxmind-db / reader / ext / maxminddb.c
matomo / app / vendor / prefixed / maxmind-db / reader / ext Last commit date
config.m4 2 years ago config.w32 2 years ago maxminddb.c 7 months ago php_maxminddb.h 4 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