Klasse für GeoIP-Lookup
Class for GeoIP lookup
This small class allows to lookup GEO ip information form a local MySql database or directly on http://ipinfodb.com. The database source files are available as download on ipinfodb as well.
Diese kleine Klasse ermöglicht GEO-IP-Lookups von einer lokalen MySql Datenbank, oder direkt von http://ipinfodb.com. Die Datenbankquelle ist als CSV (gezipt), ebenfalls auf ipinfodb erhältlich.
Sample source code
Anwendungsbeispiel
<?php
include_once('swlib/swlib.class.php');
use sw\GeoIpLookup;
// Create instance
$geoip = new GeoIpLookup(
'geoip', // Database
'geoip', // User :)
'geoip', // Pass :)
'ip2location' // Table
);
// To setup the database you need the csv file from http://ipinfodb.com:
// $geoip->setupDatabase('/tmp/IP2LOCATION-LITE-DB11.CSV', true);
// Let's query something:
$direct_result = $geoip->lookup('85.13.138.247');
print "Direct method return = " . print_r($direct_result, true) . "\n";
print "[Getters]\n";
print '$geoip->getIp() = ' . $geoip->getIp() . "\n";
print '$geoip->getCountryCode() = ' . $geoip->getCountryCode() . "\n";
print '$geoip->getCountryName() = ' . $geoip->getCountryName() . "\n";
print '$geoip->getRegionName() = ' . $geoip->getRegionName() . "\n";
print '$geoip->getZipCode() = ' . $geoip->getZipCode() . "\n";
print '$geoip->getCity() = ' . $geoip->getCity() . "\n";
print '$geoip->getLatitude() = ' . $geoip->getLatitude() . "\n";
print '$geoip->getLongitude() = ' . $geoip->getLongitude() . "\n";
print '$geoip->isFromLocalDatabase() = ' . ($geoip->isFromLocalDatabase() ? 'yes' : 'no') . "\n";
print "\n";
Output
Ausgabe
$ php geolookup.test.php
Direct method return = Array
(
[ip] => 85.13.138.247
[country_code] => de
[country_name] => GERMANY
[region_name] => BERLIN
[city_name] => BERLIN
[zip_code] => 10178
[latitude] => 52.52437
[longitude] => 13.41053
[time_zone] => +02:00
)
[Getters]
$geoip->getIp() = 85.13.138.247
$geoip->getCountryCode() = de
$geoip->getCountryName() = GERMANY
$geoip->getRegionName() = BERLIN
$geoip->getZipCode() = 10178
$geoip->getCity() = BERLIN
$geoip->getLatitude() = 52.52437
$geoip->getLongitude() = 13.41053
$geoip->isFromLocalDatabase() = yes
Class source code
Klassen-Quelltext
<?php
/**
* Performs a lookup at http://ipinfodb.com
* @gpackage de.atwillys.sw.php.swlib.util
* @author Stefan Wilhelm
* @copyright Stefan Wilhelm, 2010
* @license GPL
* @version 1.0
*/
namespace sw;
class GeoIpLookup {
/**
*
* @var array
*/
private $database = array(
);
/**
* Data received
* @var array
*/
private $data = array();
/**
* @param string $csv_file
* @param bool $print_verbose = false
*/
public function setupDatabase($csv_file='', $print_verbose=false) {
$db = $this->database;
$mysqli = new \mysqli($db['host'], $db['user'], $db['pass'], $db['db'], $db['port']);
if($mysqli->connect_error) {
throw new LException("Failed to connect to local IP database: :error", array(':error' => $mysqli->connect_error));
}
$file = fopen($csv_file, 'r');
if(!$file) {
throw new LException("Failed to open geoip import file.");
}
$table = $mysqli->escape_string($db['table']);
//
// Import as defined on http://ipinfodb.com
//
$mysqli->query("DROP TABLE IF EXISTS `$table`");
if($mysqli->error) {
throw new LException("Failed to remove old GeoIP table: :error", array(':error' => $mysqli->error));
}
$mysqli->query("
CREATE TABLE `$table` (
`ip_from` INT(10) UNSIGNED,
`ip_to` INT(10) UNSIGNED,
`country_code` CHAR(2),
`country_name` VARCHAR(64),
`region_name` VARCHAR(128),
`city_name` VARCHAR(128),
`latitude` DOUBLE,
`longitude` DOUBLE,
`zip_code` VARCHAR(30),
`time_zone` VARCHAR(8),
INDEX `idx_ip_from` (`ip_from`),
INDEX `idx_ip_to` (`ip_to`),
INDEX `idx_ip_from_to` (`ip_from`, `ip_to`)
) ENGINE=MyISAM DEFAULT CHARSET=utf8 COLLATE=utf8_bin;
");
if($mysqli->error) {
throw new LException("Creating IP lookup table failed: :error", array(':error' => $mysqli->error));
}
// Ignore first line
$keys = array(
'ip_from', 'ip_to', 'country_code', 'country_name',
'region_name', 'city_name', 'latitude', 'longitude',
'zip_code', 'time_zone'
);
$count = count($keys);
$query_base = "INSERT INTO `$table` (`" . implode("`,`", $keys) . "`) VALUES";
fgets($file); // Ignore first line.
$ok = true;
$values = array();
$n = 0;
@ignore_user_abort(true);
// Iterate lines
while(!feof($file)) {
if(($line = fgets($file)) === false) {
if(feof($file)) break;
if($print_verbose) print "[err] Failed to read file (line $n)\n";
$ok = false;
break;
}
$line = trim($line, "\n\r ");
if(empty($line)) {
continue;
}
$csv = str_getcsv($line);
if(count($csv) != $count) {
if($print_verbose) print "[err] Ignored line '$line' because the number the number of elements does not match.\n";
$ok = false;
continue;
}
foreach($csv as $k => $v) {
$csv[$k] = "'" . $mysqli->escape_string(trim($v)) . "'";
}
$values[] = "(" . implode(',', $csv) . ") ";
$n++;
if(count($values) >= 1000) {
@set_time_limit(20);
$mysqli->query($query_base . implode(',', $values));
$values = array();
if($mysqli->error) {
if($print_verbose) print "[err] in or before line $n: " . $mysqli->error . "\n";
$ok = false;
} else {
if($print_verbose) print "$n\n";
}
}
}
// Finish
if(!empty($values)) {
$mysqli->query($query_base . implode(',', $values));
if($mysqli->error) {
if($print_verbose) print "[err] in or before line $n: " . $mysqli->error . "\n";
$ok = false;
} else {
if($print_verbose) print "$n\n";
}
}
$mysqli->close();
fclose($file);
return $ok;
}
/**
* Constructor, optional with local database
* @param MySql $database
* @param string $table
*/
public function __construct($database='', $user='', $pass='', $table='ip2location_db11', $host='localhost', $port=3306) {
if(strlen($database) > 0) {
$this->database = array(
'db' => $database,
'user' => $user,
'pass' => $pass,
'table' => $table,
'host' => $host,
'port' => $port
);
}
}
/**
* Returns the data obtained from the lookup
* @return array
*/
public function getAllData() {
return $this->data;
}
/**
* Returns the IP
* @return string
*/
public function getIp() {
return isset($this->data['ip']) ? $this->data['ip'] : '';
}
/**
* Returns the country code
* @return string
*/
public function getCountryCode() {
return isset($this->data['country_code']) ? $this->data['country_code'] : '';
}
/**
* Returns the country name
* @return string
*/
public function getCountryName() {
return isset($this->data['country_name']) ? $this->data['country_name'] : '';
}
/**
* Returns the region name
* @return string
*/
public function getRegionName() {
return isset($this->data['region_name']) ? $this->data['region_name'] : '';
}
/**
* Returns the city
* @return string
*/
public function getCity() {
return isset($this->data['city_name']) ? $this->data['city_name'] : '';
}
/**
* Returns the zippostalcode
* @return string
*/
public function getZipCode() {
return isset($this->data['zip_code']) ? $this->data['zip_code'] : '';
}
/**
* Returns the latitude
* @return string
*/
public function getLatitude() {
return isset($this->data['latitude']) ? $this->data['latitude'] : '';
}
/**
* Returns the longitude
* @return string
*/
public function getLongitude() {
return isset($this->data['longitude']) ? $this->data['longitude'] : '';
}
/**
* Returns if the data are fetched from the local MySQL database.
* @return bool
*/
public function isFromLocalDatabase() {
return !isset($this->data['status']);
}
/**
* Performs the lookup
* @param string $ip = ''
* @param bool $remote_lookup_if_locally_not_found = false
*/
public function lookup($ip='', $remote_lookup_if_locally_not_found=false) {
$ip = trim($ip);
if (empty($ip)) $ip = Session::getClientIpAddress();
if (!preg_match('/^[\d]{1,3}.[\d]{1,3}.[\d]{1,3}.[\d]{1,3}$/', $ip)) {
throw new LException('Invalid IP address: ":ip"', array(':ip' => $ip));
}
// Local lookups are detailed as far as the table is a city table.
$this->data = array('ip' => $ip);
if (!empty($this->database)) {
$db = $this->database;
$mysqli = new \mysqli($db['host'], $db['user'], $db['pass'], $db['db'], $db['port']);
if($mysqli->connect_error) {
throw new LException("Failed to connect to local IP database: :error", array(':error' => $mysqli->connect_error));
}
$ip = $mysqli->escape_string($ip);
$tbl = trim($mysqli->escape_string($db['table']), "' ");
$r = $mysqli->query("SELECT * FROM `$tbl` WHERE `ip_from` <= INET_ATON('$ip') order by ip_from desc limit 1;");
if($mysqli->error) {
throw new LException("IP query failed: :error", array(':error' => $mysqli->error));
}
$r = $r->fetch_assoc();
$mysqli->close();
if (!empty($r)) {
$r = array_change_key_case($r, CASE_LOWER);
$this->data = array(
'ip' => $ip,
'country_code' => $r['country_code'],
'country_name' => isset($r['country_name']) ? $r['country_name'] : '',
'region_name' => isset($r['region_name']) ? $r['region_name'] : '',
'city_name' => isset($r['city_name']) ? $r['city_name'] : '',
'zip_code' => isset($r['zip_code']) ? $r['zip_code'] : '',
'latitude' => isset($r['latitude']) ? $r['latitude'] : '',
'longitude' => isset($r['longitude']) ? $r['longitude'] : '',
'time_zone' => isset($r['time_zone']) ? $r['time_zone'] : ''
);
}
}
// If there are no local data, perform a remote lookup
if ($remote_lookup_if_locally_not_found && count($this->data) < 2) {
$rq = new HttpRequest();
$rq->request("http://ipinfodb.com/ip_query.php?ip=$ip&output=json&timezone=false");
$o = trim($rq->getOutput(), " \t\n\r");
if (empty($o)) {
throw new LException('Geo-IP lookup has returned an empty output');
} else {
$o = json_decode($o, true);
if (empty($o)) {
throw new LException('Geo-IP lookup has returned an empty valid output (JSON decode failed)');
} else {
$this->data = $o;
}
}
}
// Normalize ...
$this->data = array_change_key_case($this->data, CASE_LOWER);
$this->data['country_code'] = strtolower($this->data['country_code']);
return $this->data;
}
}