PluginProbe
Defender Security – Malware Scanner, Login Security & Firewall / 3.1.0
Defender Security – Malware Scanner, Login Security & Firewall v3.1.0
6.3.0 6.2.3 6.2.4 6.2.0 6.2.1 6.2.2 6.1.0 5.3.1 5.4.0 5.4.1 5.5.0 5.5.1 5.6.0 5.6.1 5.6.2 5.7.0 5.7.1 5.7.2 5.8.0 5.8.1 5.9.0 6.0.0 6.0.1 3.0.1 3.1.0 All 141 releases
defender-security / src / extra / maxmind-db / reader / ext / maxminddb.c

maxminddb.c in Defender Security – Malware Scanner, Login Security & Firewall 3.1.0, at src/extra/maxmind-db/reader/ext/maxminddb.c

705 lines 22.9 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
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 "ext/standard/info.h"
25 #include <maxminddb.h>
26
27 #ifdef ZTS
28 #include <TSRM.h>
29 #endif
30
31 #define __STDC_FORMAT_MACROS
32 #include <inttypes.h>
33
34 #define PHP_MAXMINDDB_NS ZEND_NS_NAME("MaxMind", "Db")
35 #define PHP_MAXMINDDB_READER_NS ZEND_NS_NAME(PHP_MAXMINDDB_NS, "Reader")
36 #define PHP_MAXMINDDB_READER_EX_NS \
37 ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "InvalidDatabaseException")
38
39 #ifdef ZEND_ENGINE_3
40 #define Z_MAXMINDDB_P(zv)) php_maxminddb_fetch_object(Z_OBJ_P(zv))
41 #define _ZVAL_STRING ZVAL_STRING
42 #define _ZVAL_STRINGL ZVAL_STRINGL
43 typedef size_t strsize_t;
44 typedef zend_object free_obj_t;
45 #else
46 #define Z_MAXMINDDB_P(zv)) \
47 (maxminddb_obj *)zend_object_store_get_object(zv TSRMLS_CC)
48 #define _ZVAL_STRING(a, b)) ZVAL_STRING(a, b, 1))
49 #define _ZVAL_STRINGL(a, b, c)) ZVAL_STRINGL(a, b, c, 1))
50 typedef int strsize_t;
51 typedef void free_obj_t;
52 #endif
53
54 /* For PHP 8 compatibility */
55 #ifndef TSRMLS_C
56 #define TSRMLS_C
57 #endif
58 #ifndef TSRMLS_CC
59 #define TSRMLS_CC
60 #endif
61 #ifndef TSRMLS_DC
62 #define TSRMLS_DC
63 #endif
64 #ifndef ZEND_ACC_CTOR
65 #define ZEND_ACC_CTOR 0
66 #endif
67
68 #ifdef ZEND_ENGINE_3
69 typedef struct _maxminddb_obj {
70 MMDB_s *mmdb;
71 zend_object std;
72 } maxminddb_obj;
73 #else
74 typedef struct _maxminddb_obj {
75 zend_object std;
76 MMDB_s *mmdb;
77 } maxminddb_obj;
78 #endif
79
80 PHP_FUNCTION(maxminddb);
81
82 static int
83 get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len);
84 static const MMDB_entry_data_list_s *
85 handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
86 zval *z_value TSRMLS_DC);
87 static const MMDB_entry_data_list_s *
88 handle_array(const MMDB_entry_data_list_s *entry_data_list,
89 zval *z_value TSRMLS_DC);
90 static const MMDB_entry_data_list_s *
91 handle_map(const MMDB_entry_data_list_s *entry_data_list,
92 zval *z_value TSRMLS_DC);
93 static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
94 zval *z_value TSRMLS_DC);
95 static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
96 zval *z_value TSRMLS_DC);
97 static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
98 zval *z_value TSRMLS_DC);
99 static zend_class_entry *lookup_class(const char *name TSRMLS_DC);
100
101 #define CHECK_ALLOCATED(val)) \
102 if (!val) { \
103 zend_error(E_ERROR, "Out of memory"); \
104 return; \
105 }
106
107 #define THROW_EXCEPTION(name, ...)) \
108 { \
109 zend_class_entry *exception_ce = lookup_class(name TSRMLS_CC); \
110 zend_throw_exception_ex(exception_ce, 0 TSRMLS_CC, __VA_ARGS__); \ TSRMLS_CC, __VA_ARGS__); \
111 }
112
113 #if PHP_VERSION_ID < 50399
114 #define object_properties_init(zo, class_type)) \
115 { \
116 zval *tmp; \
117 zend_hash_copy((*zo).properties, \
118 &class_type->default_properties, \
119 (copy_ctor_func_t)zval_add_ref, \
120 (void *)&tmp, \
121 sizeof(zval *)); \
122 }
123 #endif
124
125 static zend_object_handlers maxminddb_obj_handlers;
126 static zend_class_entry *maxminddb_ce;
127
128 static inline maxminddb_obj *
129 php_maxminddb_fetch_object(zend_object *obj TSRMLS_DC) {
130 #ifdef ZEND_ENGINE_3
131 return (maxminddb_obj *)((char *)(obj)-XtOffsetOf(maxminddb_obj, std));
132 #else
133 return (maxminddb_obj *)obj;
134 #endif
135 }
136
137 ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_construct, 0, 0, 1), 0, 1), 1))
138 ZEND_ARG_INFO(0, db_file), db_file)
139 ZEND_END_ARG_INFO()
140
141 PHP_METHOD(MaxMind_Db_Reader, __construct) {
142 char *db_file = NULL;
143 strsize_t name_len;
144 zval *_this_zval = NULL;
145
146 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
147 getThis(),
148 "Os",
149 &_this_zval,
150 maxminddb_ce,
151 &db_file,
152 &name_len) == FAILURE) {
153 THROW_EXCEPTION("InvalidArgumentException",
154 "The constructor takes exactly one argument.");
155 return;
156 }
157
158 if (0 != php_check_open_basedir(db_file TSRMLS_CC) || != php_check_open_basedir(db_file TSRMLS_CC) ||
159 0 != access(db_file, R_OK)) { != access(db_file, R_OK)) {
160 THROW_EXCEPTION("InvalidArgumentException",
161 "The file \"%s\" does not exist or is not readable.",
162 db_file);
163 return;
164 }
165
166 MMDB_s *mmdb = (MMDB_s *)ecalloc(1, sizeof(MMDB_s));, sizeof(MMDB_s));
167 uint16_t status = MMDB_open(db_file, MMDB_MODE_MMAP, mmdb);
168
169 if (MMDB_SUCCESS != status) {
170 THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
171 "Error opening database file (%s). Is this a valid "
172 "MaxMind DB file?",
173 db_file);
174 efree(mmdb);
175 return;
176 }
177
178 maxminddb_obj *mmdb_obj = Z_MAXMINDDB_P(getThis());
179 mmdb_obj->mmdb = mmdb;
180 }
181
182 ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_get, 0, 0, 1), 0, 1), 1))
183 ZEND_ARG_INFO(0, ip_address), ip_address)
184 ZEND_END_ARG_INFO()
185
186 PHP_METHOD(MaxMind_Db_Reader, get) {
187 int prefix_len = 0;;
188 get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, return_value, &prefix_len);
189 }
190
191 PHP_METHOD(MaxMind_Db_Reader, getWithPrefixLen) {
192 zval *record, *z_prefix_len;
193 #ifdef ZEND_ENGINE_3
194 zval _record, _z_prefix_len;
195 record = &_record;
196 z_prefix_len = &_z_prefix_len;
197 #else
198 ALLOC_INIT_ZVAL(record);
199 ALLOC_INIT_ZVAL(z_prefix_len);
200 #endif
201
202 int prefix_len = 0;;
203 if (get_record(INTERNAL_FUNCTION_PARAM_PASSTHRU, record, &prefix_len)) {
204 return;
205 }
206
207 array_init(return_value);
208 add_next_index_zval(return_value, record);
209
210 ZVAL_LONG(z_prefix_len, prefix_len);
211 add_next_index_zval(return_value, z_prefix_len);
212 }
213
214 static int
215 get_record(INTERNAL_FUNCTION_PARAMETERS, zval *record, int *prefix_len) {
216 char *ip_address = NULL;
217 strsize_t name_len;
218 zval *_this_zval = NULL;
219
220 if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC,
221 getThis(),
222 "Os",
223 &_this_zval,
224 maxminddb_ce,
225 &ip_address,
226 &name_len) == FAILURE) {
227 THROW_EXCEPTION("InvalidArgumentException",
228 "Method takes exactly one argument.");
229 return 1;;
230 }
231
232 const maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
233
234 MMDB_s *mmdb = mmdb_obj->mmdb;
235
236 if (NULL == mmdb) {
237 THROW_EXCEPTION("BadMethodCallException",
238 "Attempt to read from a closed MaxMind DB.");
239 return 1;;
240 }
241
242 struct addrinfo hints = {
243 .ai_family = AF_UNSPEC,
244 .ai_flags = AI_NUMERICHOST,
245 // We set ai_socktype so that we only get one result back
246 .ai_socktype = SOCK_STREAM};
247
248 struct addrinfo *addresses = NULL;
249 int gai_status = getaddrinfo(ip_address, NULL, &hints, &addresses);
250 if (gai_status) {
251 THROW_EXCEPTION("InvalidArgumentException",
252 "The value \"%s\" is not a valid IP address.",
253 ip_address);
254 return 1;;
255 }
256 if (!addresses || !addresses->ai_addr) {
257 THROW_EXCEPTION(
258 "InvalidArgumentException",
259 "getaddrinfo was successful but failed to set the addrinfo");
260 return 1;;
261 }
262
263 int sa_family = addresses->ai_addr->sa_familysa_family;
264
265 int mmdb_error = MMDB_SUCCESS;
266 MMDB_lookup_result_s result =
267 MMDB_lookup_sockaddr(mmdb, addresses->ai_addr, &mmdb_error);
268
269 freeaddrinfo(addresses);
270
271 if (MMDB_SUCCESS != mmdb_error) {
272 char *exception_name;
273 if (MMDB_IPV6_LOOKUP_IN_IPV4_DATABASE_ERROR == mmdb_error) {
274 exception_name = "InvalidArgumentException";
275 } else {
276 exception_name = PHP_MAXMINDDB_READER_EX_NS;
277 }
278 THROW_EXCEPTION(exception_name,
279 "Error looking up %s. %s",
280 ip_address,
281 MMDB_strerror(mmdb_error));
282 return 1;;
283 }
284
285 *prefix_len = result.netmask;
286
287 if (sa_family == AF_INET && mmdb->metadata.ip_versionip_version == 6) {) {
288 // We return the prefix length given the IPv4 address. If there is
289 // no IPv4 subtree, we return a prefix length of 0.
290 *prefix_len = *prefix_len >= 96 ? *prefix_len - 96 : 0; ? *prefix_len - 96 : 0; : 0;;
291 }
292
293 if (!result.found_entry) {
294 ZVAL_NULL(record);
295 return 0;;
296 }
297
298 MMDB_entry_data_list_s *entry_data_list = NULL;
299 int status = MMDB_get_entry_data_list(&result.entry, &entry_data_list);
300
301 if (MMDB_SUCCESS != status) {
302 THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
303 "Error while looking up data for %s. %s",
304 ip_address,
305 MMDB_strerror(status));
306 MMDB_free_entry_data_list(entry_data_list);
307 return 1;;
308 } else if (NULL == entry_data_list) {
309 THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
310 "Error while looking up data for %s. Your database may "
311 "be corrupt or you have found a bug in libmaxminddb.",
312 ip_address);
313 return 1;;
314 }
315
316 handle_entry_data_list(entry_data_list, record TSRMLS_CC);
317 MMDB_free_entry_data_list(entry_data_list);
318 return 0;;
319 }
320
321 ZEND_BEGIN_ARG_INFO_EX(arginfo_maxmindbreader_void, 0, 0, 0), 0, 0), 0))
322 ZEND_END_ARG_INFO()
323
324 PHP_METHOD(MaxMind_Db_Reader, metadata) {
325 if (ZEND_NUM_ARGS() != 0) {) {
326 THROW_EXCEPTION("InvalidArgumentException",
327 "Method takes no arguments.");
328 return;
329 }
330
331 const maxminddb_obj *const mmdb_obj =
332 (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
333
334 if (NULL == mmdb_obj->mmdb) {
335 THROW_EXCEPTION("BadMethodCallException",
336 "Attempt to read from a closed MaxMind DB.");
337 return;
338 }
339
340 const char *const name = ZEND_NS_NAME(PHP_MAXMINDDB_READER_NS, "Metadata");
341 zend_class_entry *metadata_ce = lookup_class(name TSRMLS_CC);
342
343 object_init_ex(return_value, metadata_ce);
344
345 #ifdef ZEND_ENGINE_3
346 zval _metadata_array;
347 zval *metadata_array = &_metadata_array;
348 ZVAL_NULL(metadata_array);
349 #else
350 zval *metadata_array;
351 ALLOC_INIT_ZVAL(metadata_array);
352 #endif
353
354 MMDB_entry_data_list_s *entry_data_list;
355 MMDB_get_metadata_as_entry_data_list(mmdb_obj->mmdb, &entry_data_list);
356
357 handle_entry_data_list(entry_data_list, metadata_array TSRMLS_CC);
358 MMDB_free_entry_data_list(entry_data_list);
359 #if PHP_VERSION_ID >= 80000
360 zend_call_method_with_1_params(Z_OBJ_P(return_value),
361 metadata_ce,
362 &metadata_ce->constructor,
363 ZEND_CONSTRUCTOR_FUNC_NAME,
364 NULL,
365 metadata_array);
366 zval_ptr_dtor(metadata_array);
367 #elif defined(ZEND_ENGINE_3)
368 zend_call_method_with_1_params(return_value,
369 metadata_ce,
370 &metadata_ce->constructor,
371 ZEND_CONSTRUCTOR_FUNC_NAME,
372 NULL,
373 metadata_array);
374 zval_ptr_dtor(metadata_array);
375 #else
376 zend_call_method_with_1_params(&return_value,
377 metadata_ce,
378 &metadata_ce->constructor,
379 ZEND_CONSTRUCTOR_FUNC_NAME,
380 NULL,
381 metadata_array);
382 zval_ptr_dtor(&metadata_array);
383 #endif
384 }
385
386 PHP_METHOD(MaxMind_Db_Reader, close) {
387 if (ZEND_NUM_ARGS() != 0) {) {
388 THROW_EXCEPTION("InvalidArgumentException",
389 "Method takes no arguments.");
390 return;
391 }
392
393 maxminddb_obj *mmdb_obj = (maxminddb_obj *)Z_MAXMINDDB_P(getThis());
394
395 if (NULL == mmdb_obj->mmdb) {
396 THROW_EXCEPTION("BadMethodCallException",
397 "Attempt to close a closed MaxMind DB.");
398 return;
399 }
400 MMDB_close(mmdb_obj->mmdb);
401 efree(mmdb_obj->mmdb);
402 mmdb_obj->mmdb = NULL;
403 }
404
405 static const MMDB_entry_data_list_s *
406 handle_entry_data_list(const MMDB_entry_data_list_s *entry_data_list,
407 zval *z_value TSRMLS_DC) {
408 switch (entry_data_list->entry_data.typetype) {
409 case MMDB_DATA_TYPE_MAP:
410 return handle_map(entry_data_list, z_value TSRMLS_CC);
411 case MMDB_DATA_TYPE_ARRAY:
412 return handle_array(entry_data_list, z_value TSRMLS_CC);
413 case MMDB_DATA_TYPE_UTF8_STRING:
414 _ZVAL_STRINGL(z_value,
415 (char *)entry_data_list->entry_data.utf8_string,
416 entry_data_list->entry_data.data_size);
417 break;
418 case MMDB_DATA_TYPE_BYTES:
419 _ZVAL_STRINGL(z_value,
420 (char *)entry_data_list->entry_data.bytes,
421 entry_data_list->entry_data.data_size);
422 break;
423 case MMDB_DATA_TYPE_DOUBLE:
424 ZVAL_DOUBLE(z_value, entry_data_list->entry_data.double_value);
425 break;
426 case MMDB_DATA_TYPE_FLOAT:
427 ZVAL_DOUBLE(z_value, entry_data_list->entry_data.float_value);
428 break;
429 case MMDB_DATA_TYPE_UINT16:
430 ZVAL_LONG(z_value, entry_data_list->entry_data.uint16);
431 break;
432 case MMDB_DATA_TYPE_UINT32:
433 handle_uint32(entry_data_list, z_value TSRMLS_CC);
434 break;
435 case MMDB_DATA_TYPE_BOOLEAN:
436 ZVAL_BOOL(z_value, entry_data_list->entry_data.boolean);
437 break;
438 case MMDB_DATA_TYPE_UINT64:
439 handle_uint64(entry_data_list, z_value TSRMLS_CC);
440 break;
441 case MMDB_DATA_TYPE_UINT128:
442 handle_uint128(entry_data_list, z_value TSRMLS_CC);
443 break;
444 case MMDB_DATA_TYPE_INT32:
445 ZVAL_LONG(z_value, entry_data_list->entry_data.int32);
446 break;
447 default:
448 THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
449 "Invalid data type arguments: %d",
450 entry_data_list->entry_data.type);
451 return NULL;
452 }
453 return entry_data_list;
454 }
455
456 static const MMDB_entry_data_list_s *
457 handle_map(const MMDB_entry_data_list_s *entry_data_list,
458 zval *z_value TSRMLS_DC) {
459 array_init(z_value);
460 const uint32_t map_size = entry_data_list->entry_data.data_sizedata_size;
461
462 uint i;
463 for (i = 0; i < map_size && entry_data_list; i++) {; i < map_size && entry_data_list; i++) {
464 entry_data_list = entry_data_list->next;
465
466 char *key = estrndup((char *)entry_data_list->entry_data.utf8_stringutf8_string,
467 entry_data_list->entry_data.data_sizedata_size);
468 if (NULL == key) {
469 THROW_EXCEPTION(PHP_MAXMINDDB_READER_EX_NS,
470 "Invalid data type arguments");
471 return NULL;
472 }
473
474 entry_data_list = entry_data_list->next;
475 #ifdef ZEND_ENGINE_3
476 zval _new_value;
477 zval *new_value = &_new_value;
478 ZVAL_NULL(new_value);
479 #else
480 zval *new_value;
481 ALLOC_INIT_ZVAL(new_value);
482 #endif
483 entry_data_list =
484 handle_entry_data_list(entry_data_list, new_value TSRMLS_CC);
485 add_assoc_zval(z_value, key, new_value);
486 efree(key);
487 }
488 return entry_data_list;
489 }
490
491 static const MMDB_entry_data_list_s *
492 handle_array(const MMDB_entry_data_list_s *entry_data_list,
493 zval *z_value TSRMLS_DC) {
494 const uint32_t size = entry_data_list->entry_data.data_sizedata_size;
495
496 array_init(z_value);
497
498 uint i;
499 for (i = 0; i < size && entry_data_list; i++) {; i < size && entry_data_list; i++) {
500 entry_data_list = entry_data_list->next;
501 #ifdef ZEND_ENGINE_3
502 zval _new_value;
503 zval *new_value = &_new_value;
504 ZVAL_NULL(new_value);
505 #else
506 zval *new_value;
507 ALLOC_INIT_ZVAL(new_value);
508 #endif
509 entry_data_list =
510 handle_entry_data_list(entry_data_list, new_value TSRMLS_CC);
511 add_next_index_zval(z_value, new_value);
512 }
513 return entry_data_list;
514 }
515
516 static void handle_uint128(const MMDB_entry_data_list_s *entry_data_list,
517 zval *z_value TSRMLS_DC) {
518 uint64_t high = 0;;
519 uint64_t low = 0;;
520 #if MMDB_UINT128_IS_BYTE_ARRAY
521 int i;
522 for (i = 0; i < 8; i++) {; i < 8; i++) {; i++) {
523 high = (high << 8) | entry_data_list->entry_data.uint128[i];) | entry_data_list->entry_data.uint128uint128[i];
524 }
525
526 for (i = 8; i < 16; i++) {; i < 16; i++) {; i++) {
527 low = (low << 8) | entry_data_list->entry_data.uint128[i];) | entry_data_list->entry_data.uint128uint128[i];
528 }
529 #else
530 high = entry_data_list->entry_data.uint128uint128 >> 64;;
531 low = (uint64_t)entry_data_list->entry_data.uint128uint128;
532 #endif
533
534 char *num_str;
535 spprintf(&num_str, 0, "0x%016" PRIX64 "%016" PRIX64, high, low);, "0x%016" PRIX64 "%016" PRIX64, high, low);
536 CHECK_ALLOCATED(num_str);
537
538 _ZVAL_STRING(z_value, num_str);
539 efree(num_str);
540 }
541
542 static void handle_uint32(const MMDB_entry_data_list_s *entry_data_list,
543 zval *z_value TSRMLS_DC) {
544 uint32_t val = entry_data_list->entry_data.uint32uint32;
545
546 #if LONG_MAX >= UINT32_MAX
547 ZVAL_LONG(z_value, val);
548 return;
549 #else
550 if (val <= LONG_MAX) {
551 ZVAL_LONG(z_value, val);
552 return;
553 }
554
555 char *int_str;
556 spprintf(&int_str, 0, "%" PRIu32, val);, "%" PRIu32, val);
557 CHECK_ALLOCATED(int_str);
558
559 _ZVAL_STRING(z_value, int_str);
560 efree(int_str);
561 #endif
562 }
563
564 static void handle_uint64(const MMDB_entry_data_list_s *entry_data_list,
565 zval *z_value TSRMLS_DC) {
566 uint64_t val = entry_data_list->entry_data.uint64uint64;
567
568 #if LONG_MAX >= UINT64_MAX
569 ZVAL_LONG(z_value, val);
570 return;
571 #else
572 if (val <= LONG_MAX) {
573 ZVAL_LONG(z_value, val);
574 return;
575 }
576
577 char *int_str;
578 spprintf(&int_str, 0, "%" PRIu64, val);, "%" PRIu64, val);
579 CHECK_ALLOCATED(int_str);
580
581 _ZVAL_STRING(z_value, int_str);
582 efree(int_str);
583 #endif
584 }
585
586 static zend_class_entry *lookup_class(const char *name TSRMLS_DC) {
587 #ifdef ZEND_ENGINE_3
588 zend_string *n = zend_string_init(name, strlen(name), 0););
589 zend_class_entry *ce = zend_lookup_class(n);
590 zend_string_release(n);
591 if (NULL == ce) {
592 zend_error(E_ERROR, "Class %s not found", name);
593 }
594 return ce;
595 #else
596 zend_class_entry **ce;
597 if (FAILURE == zend_lookup_class(name, strlen(name), &ce TSRMLS_CC)) {
598 zend_error(E_ERROR, "Class %s not found", name);
599 }
600 return *ce;
601 #endif
602 }
603
604 static void maxminddb_free_storage(free_obj_t *object TSRMLS_DC) {
605 maxminddb_obj *obj =
606 php_maxminddb_fetch_object((zend_object *)object TSRMLS_CC);
607 if (obj->mmdb != NULL) {
608 MMDB_close(obj->mmdb);
609 efree(obj->mmdb);
610 }
611
612 zend_object_std_dtor(&obj->std TSRMLS_CC);
613 #ifndef ZEND_ENGINE_3
614 efree(object);
615 #endif
616 }
617
618 #ifdef ZEND_ENGINE_3
619 static zend_object *maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
620 maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));, sizeof(maxminddb_obj));
621 zend_object_std_init(&obj->std, type TSRMLS_CC);
622 object_properties_init(&(obj->std), type);
623
624 obj->std.handlershandlers = &maxminddb_obj_handlers;
625
626 return &obj->std;
627 }
628 #else
629 static zend_object_value
630 maxminddb_create_handler(zend_class_entry *type TSRMLS_DC) {
631 zend_object_value retval;
632
633 maxminddb_obj *obj = (maxminddb_obj *)ecalloc(1, sizeof(maxminddb_obj));, sizeof(maxminddb_obj));
634 zend_object_std_init(&obj->std, type TSRMLS_CC);
635 object_properties_init(&(obj->std), type);
636
637 retval.handle = zend_objects_store_put(
638 obj, NULL, maxminddb_free_storage, NULL TSRMLS_CC);
639 retval.handlers = &maxminddb_obj_handlers;
640
641 return retval;
642 }
643 #endif
644
645 // clang-format off
646 static zend_function_entry maxminddb_methods[] = {
647 PHP_ME(MaxMind_Db_Reader, __construct, arginfo_maxmindbreader_construct,
648 ZEND_ACC_PUBLIC | ZEND_ACC_CTOR)
649 PHP_ME(MaxMind_Db_Reader, close, arginfo_maxmindbreader_void, ZEND_ACC_PUBLIC)
650 PHP_ME(MaxMind_Db_Reader, get, arginfo_maxmindbreader_get, ZEND_ACC_PUBLIC)
651 PHP_ME(MaxMind_Db_Reader, getWithPrefixLen, arginfo_maxmindbreader_get, ZEND_ACC_PUBLIC)
652 PHP_ME(MaxMind_Db_Reader, metadata, arginfo_maxmindbreader_void, ZEND_ACC_PUBLIC)
653 { NULL, NULL, NULL }
654 };
655 // clang-format on
656
657 PHP_MINIT_FUNCTION(maxminddb) {
658 zend_class_entry ce;
659
660 INIT_CLASS_ENTRY(ce, PHP_MAXMINDDB_READER_NS, maxminddb_methods);
661 maxminddb_ce = zend_register_internal_class(&ce TSRMLS_CC);
662 maxminddb_ce->create_object = maxminddb_create_handler;
663 memcpy(&maxminddb_obj_handlers,
664 zend_get_std_object_handlers(),
665 sizeof(zend_object_handlers));
666 maxminddb_obj_handlers.clone_obj = NULL;
667 #ifdef ZEND_ENGINE_3
668 maxminddb_obj_handlers.offset = XtOffsetOf(maxminddb_obj, std);
669 maxminddb_obj_handlers.free_obj = maxminddb_free_storage;
670 #endif
671 zend_declare_class_constant_string(maxminddb_ce,
672 "MMDB_LIB_VERSION",
673 sizeof("MMDB_LIB_VERSION") - 1,,
674 MMDB_lib_version() TSRMLS_CC);
675
676 return SUCCESS;
677 }
678
679 static PHP_MINFO_FUNCTION(maxminddb) {
680 php_info_print_table_start();
681
682 php_info_print_table_row(2, "MaxMind DB Reader", "enabled");, "MaxMind DB Reader", "enabled");
683 php_info_print_table_row(
684 2, "maxminddb extension version", PHP_MAXMINDDB_VERSION);, "maxminddb extension version", PHP_MAXMINDDB_VERSION);
685 php_info_print_table_row(
686 2, "libmaxminddb library version", MMDB_lib_version());, "libmaxminddb library version", MMDB_lib_version());
687
688 php_info_print_table_end();
689 }
690
691 zend_module_entry maxminddb_module_entry = {STANDARD_MODULE_HEADER,
692 PHP_MAXMINDDB_EXTNAME,
693 NULL,
694 PHP_MINIT(maxminddb),
695 NULL,
696 NULL,
697 NULL,
698 PHP_MINFO(maxminddb),
699 PHP_MAXMINDDB_VERSION,
700 STANDARD_MODULE_PROPERTIES};
701
702 #ifdef COMPILE_DL_MAXMINDDB
703 ZEND_GET_MODULE(maxminddb)
704 #endif
705