Skip to content

Commit 03104e7

Browse files
committed
Update IP2Location PHP library
1 parent 81ca26b commit 03104e7

File tree

3 files changed

+92
-49
lines changed

3 files changed

+92
-49
lines changed

LICENSE.TXT

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
MIT License
22

3-
Copyright (c) 2017 IP2Location.com
3+
Copyright (c) 2019 IP2Location.com
44

55
Permission is hereby granted, free of charge, to any person obtaining a copy
66
of this software and associated documentation files (the "Software"), to deal

README.md

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@ This module enables users to retrieve below geolocation information from an IP a
1818
* Elevation
1919
* Usage Type
2020

21-
21+
2222
Installation
2323
------------
2424
Upload `controllers` and `libraries` to CodeIgniter `application` folder.
@@ -28,23 +28,23 @@ IP2Location BIN Database
2828
This module requires IP2Location BIN database to function. An outdated BIN database was provided in this release for your testing, but it's recommended to download the latest BIN database at the below link
2929
* IP2Location LITE BIN Database (free): https://lite.ip2location.com
3030
* IP2Location BIN Database (commercial version with high accuracy): https://www.ip2location.com
31-
31+
3232
For the BIN database update, you can just rename the downloaded BIN database to *IP2LOCATION-DB.BIN* and replace the copy in *application/libraries/ip2location/* (if you didn't change the default IP2LOCATION_DATABASE constant as described in the below section).
33-
33+
3434
IPv4 BIN vs IPv6 BIN
3535
------------------------
3636
Use the IPv4 BIN file if you just need to query IPv4 addresses.
3737

3838
Use the IPv6 BIN file if you need to query BOTH IPv4 and IPv6 addresses.
39-
39+
4040
Usage
4141
-----
4242
Use following codes in your application for get geolocation information.
4343

4444
// Define IP2Location database path (optional). By default, the IP2LOCATION_DATABASE is pointed to *application/libraries/ip2location/IP2LOCATION-DB.BIN* if you choose not to change the original settings.
4545
define('IP2LOCATION_DATABASE', '/path/to/ip2location/database');
4646

47-
// Load the IP2Location library and perform the country code lookup
47+
// Load the IP2Location library and perform the country code lookup
4848
$this->load->library('ip2location_lib');
4949
$countryCode = $this->ip2location_lib->getCountryCode('8.8.8.8');
5050

@@ -76,4 +76,4 @@ Below are the methods supported.
7676
$mobileCarrierName = $this->ip2location_lib->getMobileCarrierName($ip);
7777
$elevation = $this->ip2location_lib->getElevation($ip);
7878
$usageType = $this->ip2location_lib->getUsageType($ip);
79-
79+

libraries/ip2location/IP2Location.php

Lines changed: 85 additions & 42 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
<?php
22

33
/*
4-
* Copyright (C) 2005-2016 IP2Location.com
4+
* Copyright (C) 2005-2019 IP2Location.com
55
* All Rights Reserved
66
*
77
* This library is free software: you can redistribute it and/or
@@ -32,7 +32,7 @@ class Database {
3232
*
3333
* @var string
3434
*/
35-
const VERSION = '8.0.2';
35+
const VERSION = '8.1.0';
3636

3737
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
3838
// Error field constants ///////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -609,14 +609,17 @@ class Database {
609609
* @var array
610610
*/
611611
private $ipBase = [];
612-
613-
612+
613+
614614
//hjlim
615615
private $indexBaseAddr = [];
616616
private $year;
617617
private $month;
618618
private $day;
619619

620+
// This variable will be used to hold the raw row of columns's positions
621+
private $raw_positions_row;
622+
620623
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
621624
// Default fields //////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
622625
//////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
@@ -1063,11 +1066,13 @@ private function read($pos, $len) {
10631066
* @return string
10641067
*/
10651068
private function readString($pos, $additional = 0) {
1066-
// Get the actual pointer to the string's head
1067-
$spos = $this->readWord($pos) + $additional;
1068-
1069+
1070+
// Get the actual pointer to the string's head by extract from the raw row
1071+
$spos = unpack('V', substr($this->raw_positions_row, $pos, 4))[1] + $additional;
1072+
10691073
// Read as much as the length (first "string" byte) indicates
1070-
return $this->read($spos + 1, $this->readByte($spos + 1));
1074+
return $this->read($spos + 1, $this->readByte($spos + 1));
1075+
10711076
}
10721077

10731078
/**
@@ -1079,7 +1084,7 @@ private function readString($pos, $additional = 0) {
10791084
*/
10801085
private function readFloat($pos) {
10811086
// Unpack a float's size worth of data
1082-
return unpack('f', $this->read($pos - 1, self::$floatSize))[1];
1087+
return unpack('f', substr($this->raw_positions_row, $pos, self::$floatSize))[1];
10831088
}
10841089

10851090
/**
@@ -1142,8 +1147,8 @@ private function readCountryNameAndCode($pointer) {
11421147
// Read the country code and name (the name shares the country's pointer,
11431148
// but it must be artificially displaced 3 bytes ahead: 2 for the country code, one
11441149
// for the country name's length)
1145-
$countryCode = $this->readString($pointer + self::$columns[self::COUNTRY_CODE][$this->type]);
1146-
$countryName = $this->readString($pointer + self::$columns[self::COUNTRY_NAME][$this->type], 3);
1150+
$countryCode = $this->readString(self::$columns[self::COUNTRY_CODE][$this->type]);
1151+
$countryName = $this->readString(self::$columns[self::COUNTRY_NAME][$this->type], 3);
11471152
}
11481153

11491154
return [$countryName, $countryCode];
@@ -1165,7 +1170,7 @@ private function readRegionName($pointer) {
11651170
$regionName = self::FIELD_NOT_SUPPORTED;
11661171
} else {
11671172
// Read the region name
1168-
$regionName = $this->readString($pointer + self::$columns[self::REGION_NAME][$this->type]);
1173+
$regionName = $this->readString(self::$columns[self::REGION_NAME][$this->type]);
11691174
}
11701175
return $regionName;
11711176
}
@@ -1186,7 +1191,7 @@ private function readCityName($pointer) {
11861191
$cityName = self::FIELD_NOT_SUPPORTED;
11871192
} else {
11881193
// Read the city name
1189-
$cityName = $this->readString($pointer + self::$columns[self::CITY_NAME][$this->type]);
1194+
$cityName = $this->readString(self::$columns[self::CITY_NAME][$this->type]);
11901195
}
11911196
return $cityName;
11921197
}
@@ -1209,8 +1214,8 @@ private function readLatitudeAndLongitude($pointer) {
12091214
$longitude = self::FIELD_NOT_SUPPORTED;
12101215
} else {
12111216
// Read latitude and longitude
1212-
$latitude = $this->readFloat($pointer + self::$columns[self::LATITUDE][$this->type]);
1213-
$longitude = $this->readFloat($pointer + self::$columns[self::LONGITUDE][$this->type]);
1217+
$latitude = round($this->readFloat(self::$columns[self::LATITUDE][$this->type]), 6);
1218+
$longitude = round($this->readFloat(self::$columns[self::LONGITUDE][$this->type]), 6);
12141219
}
12151220
return [$latitude, $longitude];
12161221
}
@@ -1231,7 +1236,7 @@ private function readIsp($pointer) {
12311236
$isp = self::FIELD_NOT_SUPPORTED;
12321237
} else {
12331238
// Read isp name
1234-
$isp = $this->readString($pointer + self::$columns[self::ISP][$this->type]);
1239+
$isp = $this->readString(self::$columns[self::ISP][$this->type]);
12351240
}
12361241
return $isp;
12371242
}
@@ -1252,7 +1257,7 @@ private function readDomainName($pointer) {
12521257
$domainName = self::FIELD_NOT_SUPPORTED;
12531258
} else {
12541259
// Read the domain name
1255-
$domainName = $this->readString($pointer + self::$columns[self::DOMAIN_NAME][$this->type]);
1260+
$domainName = $this->readString(self::$columns[self::DOMAIN_NAME][$this->type]);
12561261
}
12571262
return $domainName;
12581263
}
@@ -1273,7 +1278,7 @@ private function readZipCode($pointer) {
12731278
$zipCode = self::FIELD_NOT_SUPPORTED;
12741279
} else {
12751280
// Read the zip code
1276-
$zipCode = $this->readString($pointer + self::$columns[self::ZIP_CODE][$this->type]);
1281+
$zipCode = $this->readString(self::$columns[self::ZIP_CODE][$this->type]);
12771282
}
12781283
return $zipCode;
12791284
}
@@ -1294,7 +1299,7 @@ private function readTimeZone($pointer) {
12941299
$timeZone = self::FIELD_NOT_SUPPORTED;
12951300
} else {
12961301
// Read the time zone
1297-
$timeZone = $this->readString($pointer + self::$columns[self::TIME_ZONE][$this->type]);
1302+
$timeZone = $this->readString(self::$columns[self::TIME_ZONE][$this->type]);
12981303
}
12991304
return $timeZone;
13001305
}
@@ -1315,7 +1320,7 @@ private function readNetSpeed($pointer) {
13151320
$netSpeed = self::FIELD_NOT_SUPPORTED;
13161321
} else {
13171322
// Read the net speed
1318-
$netSpeed = $this->readString($pointer + self::$columns[self::NET_SPEED][$this->type]);
1323+
$netSpeed = $this->readString(self::$columns[self::NET_SPEED][$this->type]);
13191324
}
13201325
return $netSpeed;
13211326
}
@@ -1338,8 +1343,8 @@ private function readIddAndAreaCodes($pointer) {
13381343
$areaCode = self::FIELD_NOT_SUPPORTED;
13391344
} else {
13401345
// Read IDD and area codes
1341-
$iddCode = $this->readString($pointer + self::$columns[self::IDD_CODE][$this->type]);
1342-
$areaCode = $this->readString($pointer + self::$columns[self::AREA_CODE][$this->type]);
1346+
$iddCode = $this->readString(self::$columns[self::IDD_CODE][$this->type]);
1347+
$areaCode = $this->readString(self::$columns[self::AREA_CODE][$this->type]);
13431348
}
13441349
return [$iddCode, $areaCode];
13451350
}
@@ -1362,8 +1367,8 @@ private function readWeatherStationNameAndCode($pointer) {
13621367
$weatherStationCode = self::FIELD_NOT_SUPPORTED;
13631368
} else {
13641369
// Read weather station name and code
1365-
$weatherStationName = $this->readString($pointer + self::$columns[self::WEATHER_STATION_NAME][$this->type]);
1366-
$weatherStationCode = $this->readString($pointer + self::$columns[self::WEATHER_STATION_CODE][$this->type]);
1370+
$weatherStationName = $this->readString(self::$columns[self::WEATHER_STATION_NAME][$this->type]);
1371+
$weatherStationCode = $this->readString(self::$columns[self::WEATHER_STATION_CODE][$this->type]);
13671372
}
13681373
return [$weatherStationName, $weatherStationCode];
13691374
}
@@ -1388,9 +1393,9 @@ private function readMccMncAndMobileCarrierName($pointer) {
13881393
$mobileCarrierName = self::FIELD_NOT_SUPPORTED;
13891394
} else {
13901395
// Read MCC, MNC, and mobile carrier name
1391-
$mcc = $this->readString($pointer + self::$columns[self::MCC][$this->type]);
1392-
$mnc = $this->readString($pointer + self::$columns[self::MNC][$this->type]);
1393-
$mobileCarrierName = $this->readString($pointer + self::$columns[self::MOBILE_CARRIER_NAME][$this->type]);
1396+
$mcc = $this->readString(self::$columns[self::MCC][$this->type]);
1397+
$mnc = $this->readString(self::$columns[self::MNC][$this->type]);
1398+
$mobileCarrierName = $this->readString(self::$columns[self::MOBILE_CARRIER_NAME][$this->type]);
13941399
}
13951400
return [$mcc, $mnc, $mobileCarrierName];
13961401
}
@@ -1411,7 +1416,7 @@ private function readElevation($pointer) {
14111416
$elevation = self::FIELD_NOT_SUPPORTED;
14121417
} else {
14131418
// Read the elevation
1414-
$elevation = $this->readString($pointer + self::$columns[self::ELEVATION][$this->type]);
1419+
$elevation = $this->readString(self::$columns[self::ELEVATION][$this->type]);
14151420
}
14161421
return $elevation;
14171422
}
@@ -1431,7 +1436,7 @@ private function readUsageType($pointer) {
14311436
// If the field is not suported, return accordingly
14321437
$usageType = self::FIELD_NOT_SUPPORTED;
14331438
} else {
1434-
$usageType = $this->readString($pointer + self::$columns[self::USAGE_TYPE][$this->type]);
1439+
$usageType = $this->readString(self::$columns[self::USAGE_TYPE][$this->type]);
14351440
}
14361441
return $usageType;
14371442
}
@@ -1469,7 +1474,7 @@ private function readIp($version, $pos) {
14691474
* @param int $ipNumber IP number to look for
14701475
* @return int|boolean
14711476
*/
1472-
private function binSearch($version, $ipNumber) {
1477+
private function binSearch($version, $ipNumber, $cidr=false) {
14731478
if (false === $version) {
14741479
// unrecognized version
14751480
return false;
@@ -1490,35 +1495,35 @@ private function binSearch($version, $ipNumber) {
14901495
case 4:
14911496
$ipNum1_2 = intval($ipNumber / 65536);
14921497
$indexPos = $indexBaseStart + ($ipNum1_2 << 3);
1493-
1498+
14941499
break;
1495-
1500+
14961501
case 6:
14971502
$ipNum1 = intval(bcdiv($ipNumber, bcpow('2', '112')));
14981503
$indexPos = $indexBaseStart + ($ipNum1 << 3);
14991504

15001505
break;
1501-
1506+
15021507
default:
15031508
return false;
15041509
}
1505-
1510+
15061511
$low = $this->readWord($indexPos);
15071512
$high = $this->readWord($indexPos + 4);
15081513
}
1509-
1514+
15101515
// as long as we can narrow down the search...
15111516
while ($low <= $high) {
15121517
$mid = (int) ($low + (($high - $low) >> 1));
1513-
1518+
15141519
// Read IP ranges to get boundaries
15151520
$ip_from = $this->readIp($version, $base + $width * $mid);
15161521
$ip_to = $this->readIp($version, $base + $width * ($mid + 1));
1517-
1522+
15181523
// determine whether to return, repeat on the lower half, or repeat on the upper half
15191524
switch (self::ipBetween($version, $ipNumber, $ip_from, $ip_to)) {
15201525
case 0:
1521-
return $base + $offset + $mid * $width;
1526+
return ($cidr) ? array($ip_from, $ip_to) : $base + $offset + $mid * $width;
15221527
case -1:
15231528
$high = $mid - 1;
15241529
break;
@@ -1584,14 +1589,14 @@ public function getFields($asNames = false) {
15841589
public function getModuleVersion() {
15851590
return self::VERSION;
15861591
}
1587-
1592+
15881593
/**
15891594
* Return the version of module
15901595
*/
15911596
public function getDatabaseVersion() {
15921597
return $this->year . '.' . $this->month . '.' . $this->day;
15931598
}
1594-
1599+
15951600
/**
15961601
* This function will look the given IP address up in the database and return the result(s) asked for
15971602
*
@@ -1607,20 +1612,32 @@ public function getDatabaseVersion() {
16071612
* @return mixed|array|boolean
16081613
*/
16091614
public function lookup($ip, $fields = null, $asNamed = true) {
1615+
16101616
// extract IP version and number
16111617
list($ipVersion, $ipNumber) = self::ipVersionAndNumber($ip);
16121618
// perform the binary search proper (if the IP address was invalid, binSearch will return false)
16131619
$pointer = $this->binSearch($ipVersion, $ipNumber);
1620+
if(empty($pointer)) { return false; }
16141621

16151622
// apply defaults if needed
16161623
if (null === $fields) {
16171624
$fields = $this->defaultFields;
16181625
}
16191626

1627+
// Get the entire row based on the pointer value
1628+
// The length of the row differs based on the IP version
1629+
if (4 === $ipVersion) {
1630+
$this->raw_positions_row = $this->read($pointer - 1, $this->columnWidth[4] + 4);
1631+
} elseif (6 === $ipVersion) {
1632+
$this->raw_positions_row = $this->read($pointer - 1, $this->columnWidth[6]);
1633+
}
1634+
16201635
// turn fields into an array in case it wasn't already
16211636
$ifields = (array) $fields;
1622-
// add fields if needed
1637+
1638+
// add fields if needed
16231639
if (in_array(self::ALL, $ifields)) {
1640+
16241641
$ifields[] = self::REGION_NAME;
16251642
$ifields[] = self::CITY_NAME;
16261643
$ifields[] = self::ISP;
@@ -1640,6 +1657,8 @@ public function lookup($ip, $fields = null, $asNamed = true) {
16401657
$ifields[] = self::IP_ADDRESS;
16411658
$ifields[] = self::IP_VERSION;
16421659
$ifields[] = self::IP_NUMBER;
1660+
1661+
16431662
}
16441663
// turn into a uniquely-valued array the fast way
16451664
// (see: http://php.net/manual/en/function.array-unique.php#77743)
@@ -1901,4 +1920,28 @@ public function lookup($ip, $fields = null, $asNamed = true) {
19011920
}
19021921
}
19031922

1904-
}
1923+
/**
1924+
* For a given IP address, returns the cidr of his sub-network.
1925+
*
1926+
* For example, calling get_cidr('91.200.12.233') returns '91.200.0.0/13'.
1927+
* Useful to setup "Deny From 91.200.0.0/13" in .htaccess file for Apache2
1928+
* server against spam.
1929+
* */
1930+
public function get_cidr($ip) {
1931+
// extract IP version and number
1932+
list($ipVersion, $ipNumber) = self::ipVersionAndNumber($ip);
1933+
// perform the binary search proper (if the IP address was invalid, binSearch will return false)
1934+
$resp = $this->binSearch($ipVersion, $ipNumber, true);
1935+
if(!empty($resp)) {
1936+
list($ip_from, $ip_to) = $resp;
1937+
$i=32; $mask=1;
1938+
while(($ip_to & $mask) == 0) {
1939+
$mask *= 2; $i--;
1940+
}
1941+
$ip = long2ip($ip_from);
1942+
return "$ip/$i";
1943+
}
1944+
return false;
1945+
}
1946+
1947+
}

0 commit comments

Comments
 (0)