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