changes for geoip PHP extension

This section is where GeoLite users can find support from other users.

changes for geoip PHP extension

Postby geodevel » Tue May 09, 2006 1:20 pm

Hi,
below a new version of the PHP extension file from here; see my comments at the head - hope for some comments and help of others....
Code: Select all
I created a PHP extension that allows you to find the location of an IP address - City, State,
Country, Longitude, Latitude, and other information as all, such as ISP and connection type.

To compile it, you will need to have the GeoIP c library installed.

For installation instructions for PHP extensions, see:
http://www.php.net/manual/en/install.pecl.php

Various changes introduced by G. Knauf:
- moved argument parsing up at various places before we create a GeoIP.
- moved GeoIP_delete() call at various places up to get it called before we error out.
- fixed one place where a missing return caused a segfault on all platforms because
  RETURN_STRING() was called with NULL when GeoIP lookup failed.
- changed error 'host not found' from E_WARNING to E_NOTICE since I think its a usual
  thing that the GeoIP doesnt return something in case the hostname was invalid;
  even more I think it would be better to just return an empty string, or 'N/A' and
  '--' like mod_geoip2 does, but write no error out at all.
- added php.ini entry parsing; prepared for usage of geoip.database_standard var.
  This works fine so far as you can test with the geoip_database_info() call which uses
  the database configured with the geoip.database_standard var; if not set it defaults
  to the usual place specified during compile time with GEOIPDATADIR. All other functions
  currently still ignore the geoip.database_standard setting, but default usually also
  to GEOIPDATADIR except on Win32 from what I see. Search for the dirty '//' comments ....

Since I'm very new to the GeoIP API I dont know how to specify properly the database file
when calling the functions; first trial worked with geoip_database_info(), but next did
not with geoip_country_code_by_name() - and again segfault...
So for now I would like to leave the proper calls of the GeoIP lib to someone with more
insigt - I did the PHP stuff where I'm a bit more familar with....
Also from what I see it would probably make more sense to specify a base directory rather
then the fullpath filename; but the Apache2 mod_geoip2 also takes the filename....;
so I'm asking me what about the other libs? Or can we only have one at same time?

php_geoip.c
Code:
/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2004 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.0 of the PHP license,       |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_0.txt.                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Matthew Fonda                                                |
  +----------------------------------------------------------------------+
  Please contact support@maxmind.com with any comments
*/


#define EXTENSION_VERSION "0.1.1"

#ifdef HAVE_CONFIG_H
#include "config.h"
#endif

#include <GeoIP.h>
#include <GeoIPCity.h>

#include "php.h"
#include "php_ini.h"
#include "ext/standard/info.h"
#include "php_geoip.h"



ZEND_DECLARE_MODULE_GLOBALS(geoip)

static int le_geoip;


function_entry geoip_functions[] = {
   PHP_FE(geoip_database_info,   NULL)   
   PHP_FE(geoip_country_code_by_name,   NULL)
   PHP_FE(geoip_country_name_by_name,   NULL)
   PHP_FE(geoip_org_by_name,   NULL)
   PHP_FE(geoip_record_by_name,   NULL)
   PHP_FE(geoip_id_by_name,   NULL)
   PHP_FE(geoip_region_by_name,   NULL)
   {NULL, NULL, NULL}   
};
/* }}} */

/* {{{ geoip_module_entry
*/
zend_module_entry geoip_module_entry = {
#if ZEND_MODULE_API_NO >= 20010901
   STANDARD_MODULE_HEADER,
#endif
   "geoip",
   geoip_functions,
   PHP_MINIT(geoip),
   PHP_MSHUTDOWN(geoip),
   PHP_RINIT(geoip),     
   PHP_RSHUTDOWN(geoip),   
   PHP_MINFO(geoip),
#if ZEND_MODULE_API_NO >= 20010901
   EXTENSION_VERSION, /* version number of the extension */
#endif
   STANDARD_MODULE_PROPERTIES
};
/* }}} */

#ifdef COMPILE_DL_GEOIP
ZEND_GET_MODULE(geoip)
#endif


#ifdef GEOIPDATADIR
#define GEOIPDATABASE GEOIPDATADIR "/GeoIP.dat"
#else
#define GEOIPDATABASE "GeoIP.dat"
#endif

/* }}} */

/* {{{ PHP_INI
*/
PHP_INI_BEGIN()
   STD_PHP_INI_ENTRY("geoip.database_standard", GEOIPDATABASE, PHP_INI_ALL, OnUpdateString, database_standard, zend_geoip_globals, geoip_globals)
PHP_INI_END()
/* }}} */

/* {{{ php_geoip_init_globals
*/
static void php_geoip_init_globals(zend_geoip_globals *geoip_globals)
{
   geoip_globals->database_standard = NULL;
}
/* }}} */

/* {{{ PHP_MINIT_FUNCTION
*/
PHP_MINIT_FUNCTION(geoip)
{
   ZEND_INIT_MODULE_GLOBALS(geoip, php_geoip_init_globals, NULL);
   REGISTER_INI_ENTRIES();
   return SUCCESS;
}
/* }}} */

/* {{{ PHP_MSHUTDOWN_FUNCTION
*/
PHP_MSHUTDOWN_FUNCTION(geoip)
{
   return SUCCESS;
}
/* }}} */


/* {{{ PHP_RINIT_FUNCTION
*/
PHP_RINIT_FUNCTION(geoip)
{
   return SUCCESS;
}
/* }}} */


/* {{{ PHP_RSHUTDOWN_FUNCTION
*/
PHP_RSHUTDOWN_FUNCTION(geoip)
{
   return SUCCESS;
}
/* }}} */

/* {{{ PHP_MINFO_FUNCTION
*/
PHP_MINFO_FUNCTION(geoip)
{
   php_info_print_table_start();
   php_info_print_table_header(2, "geoip support", "enabled");
   php_info_print_table_row(2, "geoip extension version", EXTENSION_VERSION);
   php_info_print_table_end();
   DISPLAY_INI_ENTRIES();
}
/* }}} */

PHP_FUNCTION(geoip_database_info)
{
   GeoIP * gi;
   char * db_info;

   if(ZEND_NUM_ARGS() != 0) {
      WRONG_PARAM_COUNT;
   }
   
   //gi = GeoIP_new(GEOIP_STANDARD);
   gi = GeoIP_open(GEOIP_G(database_standard), GEOIP_STANDARD);
   db_info = GeoIP_database_info(gi);
   GeoIP_delete(gi);
   
   RETURN_STRING(db_info, 1);
   efree(db_info);
}

PHP_FUNCTION(geoip_country_code_by_name)
{
   GeoIP * gi;
   char * hostname = NULL;
   const char * country_code;
   int arglen;

   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &arglen) == FAILURE) {
      return;
   }

   gi = GeoIP_new(GEOIP_COUNTRY_EDITION);
   //gi = GeoIP_open(GEOIP_G(database_standard), GEOIP_COUNTRY_EDITION);
   country_code = GeoIP_country_code_by_name(gi, hostname);
   GeoIP_delete(gi);
   if (country_code == NULL) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Host %s not found", hostname);
      return;
   }
   RETURN_STRING((char*)country_code, 1);
}

PHP_FUNCTION(geoip_country_name_by_name)
{
   GeoIP * gi;
   char * hostname = NULL;
   const char * country_name;
   int arglen;
   
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &arglen) == FAILURE) {
      return;
   }
   
   if (GeoIP_db_avail(GEOIP_COUNTRY_EDITION)) {
      gi = GeoIP_open_type(GEOIP_COUNTRY_EDITION, GEOIP_STANDARD);
   }   else {
      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Required database not available.");
      return;
   }
   
   country_name = GeoIP_country_name_by_name(gi, hostname);
   GeoIP_delete(gi);
   if (country_name == NULL) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Host %s not found", hostname);
      return;
   }
   RETURN_STRING((char*)country_name, 1);
}

PHP_FUNCTION(geoip_org_by_name)
{
   GeoIP * gi;
   char * hostname = NULL;
   const char * org;
   int arglen;
   
   if (GeoIP_db_avail(GEOIP_ORG_EDITION)) {
      gi = GeoIP_open_type(GEOIP_ORG_EDITION, GEOIP_STANDARD);
   }   else {
      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Required database not available");
      return;
   }
   
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &arglen) == FAILURE) {
      return;
   }
   org = GeoIP_org_by_name(gi, hostname);
   GeoIP_delete(gi);
   if (org == NULL) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Host %s not found", hostname);
      return;
   }
   RETURN_STRING((char*)org, 1);
}

PHP_FUNCTION(geoip_record_by_name)
{
   GeoIP * gi;
   char * hostname = NULL;
   int arglen;
   GeoIPRecord * gir;
   
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &arglen) == FAILURE) {
      return;
   }

   if (GeoIP_db_avail(GEOIP_CITY_EDITION_REV1)) {
      gi = GeoIP_open_type(GEOIP_CITY_EDITION_REV1, GEOIP_STANDARD);
   }   else {
      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Required database not available");
      return;
   }
   gir = GeoIP_record_by_name(gi, hostname);
   
   if (NULL == gir) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Host %s not found", hostname);
      return;
   }

   if (NULL == gir->country_code) {
      gir->country_code = "";
   }
   if (NULL == gir->region) {
      gir->region = "";
   }
   if (NULL == gir->city) {
      gir->city = "";
   }
   if (NULL == gir->postal_code) {
      gir->postal_code = "";
   }

   array_init(return_value);
   add_assoc_string(return_value, "country_code", gir->country_code, 1);
   add_assoc_string(return_value, "region", gir->region, 1);
   add_assoc_string(return_value, "city", gir->city, 1);
   add_assoc_string(return_value, "postal_code", gir->postal_code, 1);
   add_assoc_long(return_value, "latitude", gir->latitude);
   add_assoc_long(return_value, "longitude", gir->longitude);
   add_assoc_long(return_value, "dma_code", gir->dma_code);
   add_assoc_long(return_value, "area_code", gir->area_code);
   GeoIP_delete(gi);
}

PHP_FUNCTION(geoip_id_by_name)
{
   GeoIP * gi;
   char * hostname = NULL;
   int arglen;
   int netspeed;
   
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &arglen) == FAILURE) {
      return;
   }
   
   if (GeoIP_db_avail(GEOIP_NETSPEED_EDITION)) {
      gi = GeoIP_open_type(GEOIP_NETSPEED_EDITION, GEOIP_STANDARD);
   }   else {
      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Required database not available");
      return;
   }
   
   netspeed = GeoIP_id_by_name(gi, hostname);
   GeoIP_delete(gi);
   RETURN_LONG(netspeed);
   
}

PHP_FUNCTION(geoip_region_by_name)
{
   GeoIP * gi;
   char * hostname = NULL;
   int arglen;
   GeoIPRegion * region;
   
   if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &hostname, &arglen) == FAILURE) {
      return;
   }
   
   if (GeoIP_db_avail(GEOIP_REGION_EDITION_REV0) || GeoIP_db_avail(GEOIP_REGION_EDITION_REV1)) {
      if (GeoIP_db_avail(GEOIP_REGION_EDITION_REV1)) {
         gi = GeoIP_open_type(GEOIP_REGION_EDITION_REV1, GEOIP_STANDARD);
      } else {
         gi = GeoIP_open_type(GEOIP_REGION_EDITION_REV0, GEOIP_STANDARD);
      }
   }   else {
      php_error_docref(NULL TSRMLS_CC, E_WARNING, "Required database not available");
      return;
   }
   
   region = GeoIP_region_by_name(gi, hostname);
   GeoIP_delete(gi);
   
   if (NULL == region) {
      php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Host %s not found", hostname);
      return;
   }
   
   array_init(return_value);
   add_assoc_string(return_value, "country_code", region->country_code, 1);
   add_assoc_string(return_value, "region", region->region, 1);
}


/* }}} */


/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/


php_geoip.h
Code:
/*
  +----------------------------------------------------------------------+
  | PHP Version 5                                                        |
  +----------------------------------------------------------------------+
  | Copyright (c) 1997-2004 The PHP Group                                |
  +----------------------------------------------------------------------+
  | This source file is subject to version 3.0 of the PHP license,       |
  | that is bundled with this package in the file LICENSE, and is        |
  | available through the world-wide-web at the following url:           |
  | http://www.php.net/license/3_0.txt.                                  |
  | If you did not receive a copy of the PHP license and are unable to   |
  | obtain it through the world-wide-web, please send a note to          |
  | license@php.net so we can mail you a copy immediately.               |
  +----------------------------------------------------------------------+
  | Author: Matthew Fonda                                                |
  +----------------------------------------------------------------------+
  Please contact support@maxmind.com with any comments
*/

#ifndef PHP_GEOIP_H
#define PHP_GEOIP_H

extern zend_module_entry geoip_module_entry;
#define phpext_geoip_ptr &geoip_module_entry

#ifdef PHP_WIN32
#define PHP_GEOIP_API __declspec(dllexport)
#else
#define PHP_GEOIP_API
#endif

#ifdef ZTS
#include "TSRM.h"
#endif

#include <GeoIP.h>
#include <GeoIPCity.h>

PHP_MINIT_FUNCTION(geoip);
PHP_MSHUTDOWN_FUNCTION(geoip);
PHP_RINIT_FUNCTION(geoip);
PHP_RSHUTDOWN_FUNCTION(geoip);
PHP_MINFO_FUNCTION(geoip);


PHP_FUNCTION(geoip_database_info);
PHP_FUNCTION(geoip_country_code_by_name);
PHP_FUNCTION(geoip_country_name_by_name);
PHP_FUNCTION(geoip_org_by_name);
PHP_FUNCTION(geoip_record_by_name);
PHP_FUNCTION(geoip_id_by_name);
PHP_FUNCTION(geoip_region_by_name);


ZEND_BEGIN_MODULE_GLOBALS(geoip)
   char* database_standard;
ZEND_END_MODULE_GLOBALS(geoip)

#ifdef ZTS
#define GEOIP_G(v) TSRMG(geoip_globals_id, zend_geoip_globals *, v)
#else
#define GEOIP_G(v) (geoip_globals.v)
#endif

#endif /* PHP_GEOIP_H */


/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/
geodevel
 
Posts: 4
Joined: Mon May 08, 2006 10:27 pm
Location: DE

Return to GeoLite Support

Who is online

Users browsing this forum: ken and 0 guests