0.1.0 initial commit
This commit is contained in:
commit
a09ec7f5ed
9 changed files with 1016 additions and 0 deletions
115
src/IpLocator.php
Normal file
115
src/IpLocator.php
Normal file
|
|
@ -0,0 +1,115 @@
|
|||
<?php
|
||||
/**
|
||||
* (c) 2025 Sakuragasaki46
|
||||
*
|
||||
* This is an interface to the IP2Location Lite country IP database, CC BY-SA licensed
|
||||
* and accessible free of charge at <https://lite.ip2location.com> (registration required).
|
||||
* IP2Location Lite® is a registered trademark of Hexasoft Development Sdn Bhd.
|
||||
*/
|
||||
|
||||
namespace Yusurko\UserAgent;
|
||||
|
||||
|
||||
use Yusurko\UserAgent\IpAddress;
|
||||
|
||||
|
||||
class IpLocator {
|
||||
protected $conn, $source_file;
|
||||
|
||||
const SOURCE_FILE = '.err/data/IP2LOCATION-LITE-DB1.IPV6.CSV';
|
||||
|
||||
const LOCAL_RANGES = [
|
||||
["0", "1", '@'],
|
||||
["281470681743360", "281470698520575", '+'],
|
||||
["281470849515520", "281470866292735", "+"],
|
||||
["281472812449792", "281472829227007", "@"],
|
||||
["281473533739008", "281473533804543", "+"],
|
||||
["281473568473088", "281473569521663", "+"],
|
||||
["281473913978880", "281473914044415", "+"],
|
||||
["338288524927261089654018896841347694592", "338288524927261089672465640915057246207", "+"]
|
||||
];
|
||||
|
||||
public function __construct($conn, $source_file = self::SOURCE_FILE) {
|
||||
$this->conn = $conn;
|
||||
$this->source_file = $source_file;
|
||||
}
|
||||
|
||||
public function locate($addr){
|
||||
$addr = new IpAddress($addr);
|
||||
|
||||
if (!$this->isDbLoaded()) {
|
||||
$up_to_range = $this->getDbLoadedUpto();
|
||||
$this->loadCsvIntoDb($up_to_range);
|
||||
}
|
||||
|
||||
$country = $this->lookupDb($addr);
|
||||
|
||||
return new Country($country);
|
||||
}
|
||||
|
||||
private function isDbLoaded() {
|
||||
$ex = $this->conn->prepare("SELECT 1 FROM af_ip2location WHERE range_end = x'ffffffffffffffffffffffffffffffff'");
|
||||
$ex->execute();
|
||||
$res = $ex->get_result();
|
||||
|
||||
return ($res->num_rows > 0);
|
||||
}
|
||||
|
||||
private function getDbLoadedUpto(){
|
||||
$ex = $this->conn->prepare("SELECT hex(range_end) FROM af_ip2location ORDER BY id DESC LIMIT 1");
|
||||
$ex->execute();
|
||||
$ex->store_result();
|
||||
$ex->bind_result($range_end);
|
||||
$ex->fetch();
|
||||
|
||||
return IpAddress::fromHex($range_end);
|
||||
}
|
||||
|
||||
private function loadCsvIntoDb($start = false) {
|
||||
|
||||
$f = fopen($this->source_file, 'r');
|
||||
|
||||
while (($line = fgetcsv($f)) !== false) {
|
||||
$rs = new IpAddress($line[0]);
|
||||
$re = new IpAddress($line[1]);
|
||||
if ($rs->compare($start) <= 0) continue;
|
||||
try {
|
||||
$this->storeRangeIntoDb($rs, $re, $line[2]);
|
||||
} catch (\mysqli_sql_exception $ee) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private function storeRangeIntoDb($range_start, $range_end, $country) {
|
||||
$range_start_x = $range_start->toFullHex();
|
||||
$range_end_x = $range_end->toFullHex();
|
||||
$ins = $this->conn->prepare('INSERT INTO af_ip2location (range_start, range_end, country) VALUES (unhex(?), unhex(?), ?)');
|
||||
$ins->bind_param('sss', $range_start_x, $range_end_x, $country);
|
||||
$ins->execute();
|
||||
$ins->store_result();
|
||||
}
|
||||
|
||||
private function lookupDb($addr) {
|
||||
// look up forbidden ranges first
|
||||
foreach (self::LOCAL_RANGES as $rang) {
|
||||
[ $rs, $re, $co ] = $rang;
|
||||
if ($addr->compare(new IpAddress($rs)) >= 0 && $addr->compare(new IpAddress($re)) <= 0) {
|
||||
return $co;
|
||||
}
|
||||
}
|
||||
|
||||
$addr_x = $addr->toFullHex();
|
||||
$st = $this->conn->prepare('SELECT country FROM af_ip2location WHERE range_end >= unhex(?) AND range_start <= unhex(?)');
|
||||
$st->bind_param('ss', $addr_x, $addr_x);
|
||||
$st->execute();
|
||||
$res = $st->get_result();
|
||||
if ($res->num_rows < 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return $res->fetch_assoc()['country'];
|
||||
}
|
||||
}
|
||||
Loading…
Add table
Add a link
Reference in a new issue