This commit is contained in:
Kevin Adametz 2024-08-05 12:05:24 +02:00
parent 04d677d37a
commit bfa3bb1df4
1191 changed files with 637397 additions and 10619 deletions

View file

@ -0,0 +1,94 @@
<?php
/**
*
* DB-IP.com database query and management class
*
* Copyright (C) 2022 db-ip.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
namespace App\Services\dbip;
use PDO;
use Exception;
use PDOException;
use App\Models\DbipLookup;
use App\Models\DbipLookup2;
use App\Models\DbipLookup3;
use Illuminate\Support\Facades\Storage;
class DBIPException extends Exception {
}
class MyDBIP {
const VERSION = 4;
static public function lookup($addr) {
if ($ret = self::doLookup(self::addrType($addr), inet_pton($addr))) {
return $ret;
}
return false;
}
static public function doLookup($addrType, $addrStart) {
$res = DbipLookup::where('addr_type', $addrType)->where('ip_start', '<=', $addrStart)->orderBy('ip_start', 'desc')->first();
$c1 = isset($res->country) ? $res->country : null;
$res = DbipLookup2::where('addr_type', $addrType)->where('ip_start', '<=', $addrStart)->orderBy('ip_start', 'desc')->first();
$c2 = isset($res->country) ? $res->country : null;
if($c1 == $c2){
return $c1;
}
$res = DbipLookup3::where('addr_type', $addrType)->where('ip_start', '<=', $addrStart)->orderBy('ip_start', 'desc')->first();
if(isset($res->country)){
return $res->country;
}
//look in api
return false;
}
static private function addrType($addr) {
if (ip2long($addr) !== false) {
return "ipv4";
} else if (preg_match('/^[0-9a-fA-F:]+$/', $addr) && @inet_pton($addr)) {
return "ipv6";
}
throw new DBIPException("unknown address type for {$addr}");
}
static public function insert($addr, $country) {
$lookup = new DbipLookup3();
$lookup->addr_type = self::addrType($addr);
$lookup->ip_start = inet_pton($addr);
$lookup->ip_end = inet_pton($addr);
$lookup->country = strtoupper($country);
$lookup->save();
}
}

View file

@ -0,0 +1,211 @@
#!/usr/bin/env php
<?php
/**
*
* DB-IP.com CSV database format conversion tool
*
* Copyright (C) 2020 db-ip.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
$outputFormats = [
"range" => function(array $csvData, $of, string $firstIpBin, string $lastIpBin): void {
writeCSV($of, $csvData);
},
"cidr" => function(array $csvData, $of, string $firstIpBin, string $lastIpBin): void {
array_shift($csvData);
foreach (rangeToCIDR($firstIpBin, $lastIpBin) as $cidrNet) {
$csvData[0] = $cidrNet;
writeCSV($of, $csvData);
}
},
"long" => function(array $csvData, $of, string $firstIpBin, string $lastIpBin): void {
if (($firstIpLong = ip2long($csvData[0])) === false) {
throw new Exception("invalid IP address for long conversion : {$csvData[0]}");
} else if (($lastIpLong = ip2long($csvData[1])) === false) {
throw new Exception("invalid IP address for long conversion : {$csvData[1]}");
}
$csvData[0] = $firstIpLong;
$csvData[1] = $lastIpLong;
writeCSV($of, $csvData);
},
];
function writeCSV($of, $csvData) {
fputcsv($of, $csvData);
}
function vEcho(string $s): void {
if (!$GLOBALS["verbose"]) {
return;
}
echo $s;
}
function findLargestNetwork(string $ipStartBin): int {
for ($i = strlen($ipStartBin); $i--; $i >= 0) {
$byte = ord($ipStartBin[$i]);
for ($j = 7; $j >= 0; $j--) {
if ($byte & (0xff >> $j)) {
return ($i << 3) + $j + 1;
}
}
}
return 0;
}
function getLastAddress(string $ipStartBin, int $cidrBits): string {
$ret = $ipStartBin;
for ($i = strlen($ipStartBin); $i--; $i >= 0) {
$firstBit = ($i << 3) + 1;
$lastBit = ($i + 1) << 3;
if ($cidrBits > $lastBit) {
continue;
} else if ($cidrBits < $firstBit) {
$ret[$i] = "\xff";
} else {
$ret[$i] = chr(ord($ret[$i]) | (0xff >> ($cidrBits - $firstBit + 1)));
}
}
return $ret;
}
function getNextAddress(string $ipStartBin): string {
$ret = $ipStartBin;
for ($i = strlen($ipStartBin); $i--; $i >= 0) {
for ($j = 7; $j >= 0; $j--) {
$byte = ord($ret[$i]);
$mask = 1 << (7 - $j);
if ($byte & $mask) {
$ret[$i] = chr($byte & ~$mask);
} else {
$ret[$i] = chr($byte | $mask);
return $ret;
}
}
}
throw new Exception("no next address for " . inet_ntop($ipStartBin));
}
function rangeToCIDR(string $ipStartBin, string $ipEndBin): array {
if (strcmp($ipStartBin, $ipEndBin) > 0) {
throw new Exception("wrong ip address order");
}
$cidrNets = [];
$cidrBits = findLargestNetwork($ipStartBin);
do {
$lastAddrBin = getLastAddress($ipStartBin, $cidrBits);
if (($cmp = strcmp($lastAddrBin, $ipEndBin)) <= 0) {
$cidrNets[] = inet_ntop($ipStartBin) . "/" . $cidrBits;
if ($cmp === 0) {
return $cidrNets;
}
$ipStartBin = getNextAddress($lastAddrBin);
$cidrBits = findLargestNetwork($ipStartBin);
} else {
$cidrBits++;
}
} while (true);
}
try {
$exitCode = 0;
$opts = getopt("i:o:f:qhw46");
$verbose = !isset($opts["q"]);
if (!$opts || isset($opts["h"]) || !isset($opts["i"]) || !isset($opts["o"]) || !isset($opts["f"]) || (isset($opts["4"]) && isset($opts["6"]))) {
echo "usage: {$argv[0]} -i <inputFileName.csv> -o <outputFileName.csv> -f <outputFormat> [-4|-6] [-w] [-q]\n";
echo " -i input CSV file\n";
echo " -o output file name\n";
echo " -f output format (" . implode("|", array_keys($outputFormats)) . ")\n";
echo " -4 output ipv4 networks only\n";
echo " -6 output ipv6 networks only\n";
echo " -w overwrite output file if it already exists\n";
echo " -q be quiet\n";
exit(1);
}
$inputFile = $opts["i"];
if (!file_exists($inputFile)) {
throw new Exception("cannot find input file: {$inputFile}");
} else if (!is_readable($inputFile)) {
throw new Exception("cannot read input file: {$inputFile}");
}
if (substr($inputFile, -3) === ".gz") {
$inputFile = "compress.zlib://" . $inputFile;
}
if (!$if = fopen($inputFile, "r")) {
throw new Exception("cannot open input file: {$inputFile}");
}
$outputFile = $opts["o"];
if (file_exists($outputFile) && !isset($opts["w"])) {
throw new Exception("output file {$outputFile} already exists, use -w to force overwrite");
}
if (substr($outputFile, -3) === ".gz") {
$outputFile = "compress.zlib://" . $outputFile;
}
if (!$of = fopen($outputFile, "w")) {
throw new Exception("cannot open output file: {$outPutFile}");
}
if (!isset($outputFormats[$opts["f"]])) {
throw new Exception("invalid output format {$opts['f']}");
}
$outputFormatter = $outputFormats[$opts["f"]];
$i = 0;
while ($r = fgetcsv($if, 8192)) {
$i++;
[ $firstIp, $lastIp ] = $r;
try {
if (!$firstIpBin = inet_pton($firstIp)) {
throw new Exception("invalid first IP '{$firstIp}' in CSV record");
} else if (!$lastIpBin = inet_pton($lastIp)) {
throw new Exception("invalid last IP '{$lastIp}' in CSV record");
} else if (($addrLen = strlen($firstIpBin)) !== strlen($lastIpBin)) {
throw new Exception("first and last IP address family mismatch ({$firstIp} / {$lastIp})");
}
if (isset($opts["4"]) && ($addrLen !== 4)) {
continue;
} else if (isset($opts["6"]) && ($addrLen !== 16)) {
continue;
}
$outputFormatter($r, $of, $firstIpBin, $lastIpBin);
} catch (Exception $e) {
throw new Exception("line {$i}: {$e->getMessage()}");
}
}
fclose($if);
fclose($of);
vEcho("Wrote {$outputFile}\n");
} catch (Exception $e) {
if ($stdErr = @fopen("php://stderr", "w")) {
fwrite($stdErr, "ERROR: {$e->getMessage()}\n");
fclose($stdErr);
} else {
echo "ERROR: {$e->getMessage()}\n";
}
$exitCode = 1;
}
if ($exitCode) {
exit($exitCode);
}

View file

@ -0,0 +1,12 @@
1.0.0.0,1.0.0.254,AU,Australia,OC,Oceania
1.0.0.255,1.0.0.255,ID,Indonesia,AS,Asia
1.0.1.0,1.0.3.255,CN,China,AS,Asia
1.0.4.0,1.0.7.255,AU,Australia,OC,Oceania
1.0.8.0,1.0.15.255,CN,China,AS,Asia
1.0.16.0,1.0.31.255,JP,Japan,AS,Asia
1.0.32.0,1.0.63.255,CN,China,AS,Asia
1.0.64.0,1.0.127.255,JP,Japan,AS,Asia
1.0.128.0,1.0.218.40,TH,Thailand,AS,Asia
1.0.218.41,1.0.218.41,MY,Malaysia,AS,Asia
1.0.218.42,1.0.255.255,TH,Thailand,AS,Asia
1.1.0.0,1.1.0.255,CN,China,AS,Asia
1 1.0.0.0 1.0.0.254 AU Australia OC Oceania
2 1.0.0.255 1.0.0.255 ID Indonesia AS Asia
3 1.0.1.0 1.0.3.255 CN China AS Asia
4 1.0.4.0 1.0.7.255 AU Australia OC Oceania
5 1.0.8.0 1.0.15.255 CN China AS Asia
6 1.0.16.0 1.0.31.255 JP Japan AS Asia
7 1.0.32.0 1.0.63.255 CN China AS Asia
8 1.0.64.0 1.0.127.255 JP Japan AS Asia
9 1.0.128.0 1.0.218.40 TH Thailand AS Asia
10 1.0.218.41 1.0.218.41 MY Malaysia AS Asia
11 1.0.218.42 1.0.255.255 TH Thailand AS Asia
12 1.1.0.0 1.1.0.255 CN China AS Asia

File diff suppressed because it is too large Load diff

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,10 @@
[account]
; Your account key is available in your customer section at https://db-ip.com/account/
accountKey = INSERT_YOUR_ACCOUNT_KEY_HERE
[database]
; This is the PDO Data Source Name for your database instance, see http://php.net/manual/pdo.construct.php
dataSourceName = "mysql:host=localhost;dbname=myapp"
; dbUser and dbPassword are the database account credentials
dbUser = myapp
dbPassword = myapp123

327
app/Services/dbip/dbip-update.php Executable file
View file

@ -0,0 +1,327 @@
#!/usr/bin/env php
<?php
/**
*
* DB-IP.com database update tool
*
* Copyright (C) 2021 db-ip.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
require "dbip.class.php";
const API_BASE = "https://db-ip.com/account";
const DEFAULT_CONF = "dbip-update.ini";
function apiRequest($path, $key) {
$url = API_BASE . "/" . $key . "/db" . $path;
if (($jsonData = file_get_contents($url)) === false) {
throw new Exception("cannot fetch API result from {$url}");
} else if (!isset($jsonData) || !$jsonData || (($resp = json_decode($jsonData)) === false)) {
throw new Exception("cannot decode API result from {$url}");
} else if (isset($resp->error)) {
throw new Exception("API error: {$resp->error}");
}
return $resp;
}
function vEcho($s) {
if (!$GLOBALS["verbose"]) {
return false;
}
echo $s;
}
try {
$exitCode = 0;
$opts = getopt("k:d:f:o:zZqlnwb:u:p:t:c:D");
$verbose = !isset($opts["q"]);
if (isset($opts["c"])) {
if (!file_exists($opts["c"]) || !is_readable($opts["c"])) {
throw new Exception("cannot read configuration file {$opts['c']}");
}
$confName = $opts["c"];
} else if (file_exists(__DIR__ . DIRECTORY_SEPARATOR . DEFAULT_CONF) && is_readable(__DIR__ . DIRECTORY_SEPARATOR . DEFAULT_CONF)) {
$confName = __DIR__ . DIRECTORY_SEPARATOR . DEFAULT_CONF;
}
if (isset($confName)) {
if (($conf = parse_ini_file($confName)) === false) {
throw new Exception("cannot parse configuration file {$confName}");
}
$confMap = [
"accountKey" => "k",
"dbType" => "d",
"format" => "f",
"outputDir" => "o",
"outputFileName" => "o",
"dataSourceName" => "b",
"dbUser" => "u",
"dbPassword" => "p",
"dbTableName" => "t",
];
foreach ($conf as $name => $value) {
if (!isset($confMap[$name])) {
throw new Exception("invalid configuration parameter {$name}");
} else if (!isset($opts[$confMap[$name]])) {
$opts[$confMap[$name]] = $value;
}
}
}
if (!isset($opts["k"]) || !$opts["k"]) {
echo "usage: {$argv[0]} -k <accountKey> [-l] [-d <dbType>] [-f <format>] [-o <outputDir|outputFileName>] [-b <dataSourceName> [-u <dbUser>] [-p <dbPassword] [-t <dbTableName>] [-D]] [-c <configFile>] [-n] [-z|-Z] [-w] [-q]\n";
echo " -l list available items and exit\n";
echo " -n request new items only\n";
echo " -z fetch uncompressed file (default for mmdb format)\n";
echo " -Z fetch compressed file (default for csv format)\n";
echo " -w overwrite destination file if it already exists\n";
echo " -b PDO DSN for database update (ie. \"mysql:host=localhost;dbname=dbip\")\n";
echo " -u database username (default 'root')\n";
echo " -p database password (default '')\n";
echo " -t name of database table (default 'dbip_lookup')\n";
echo " -D do not use a temporary table (table specified by -t must be empty)\n";
echo " -q be quiet\n";
exit(1);
}
$apiKey = $opts["k"];
if (!isset($opts["d"])) {
$dbList = apiRequest("/", $apiKey);
if (count((array)$dbList) > 1) {
vEcho("Use -d to select a database type :\n");
foreach ($dbList as $dbType => $dbInfo) {
echo $dbType . "\n";
}
exit();
} else {
foreach ($dbList as $dbType => $dbInfo) {
break;
}
}
} else {
$dbType = $opts["d"];
}
if (isset($opts["b"])) {
if (isset($opts["o"])) {
throw new Exception("Arguments -b and -o cannot be used in the same command line");
}
$dbUser = isset($opts["u"]) ? $opts["u"] : "root";
$dbPassword = isset($opts["p"]) ? $opts["p"] : "";
$dbTable = isset($opts["t"]) ? $opts["t"] : "dbip_lookup";
$format = "csv";
try {
$dsn = $opts["b"];
if (preg_match('/^mysql:/', $dsn)) {
if (!preg_match('/charset=/', $dsn)) {
$dsn .= ";charset=utf8mb4";
}
$dbQuoteChar = '`'; // backquote for MySQL
} else {
$dbQuoteChar = '"'; // double quote for ANSI SQL
}
$db = new PDO($dsn, $dbUser, $dbPassword);
$db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$dbUseTempTable = !isset($opts["D"]);
} catch (PDOException $e) {
throw new Exception("Cannot connect to database: {$e->getMessage()}");
}
} else {
if (!isset($opts["f"])) {
$filesList = apiRequest("/{$dbType}", $apiKey);
vEcho("Use -f to specify a format for your {$dbType} subscription :\n");
foreach ($filesList as $format => $fileInfo) {
echo $format . "\n";
}
exit();
}
$format = $opts["f"];
}
$onlyNew = isset($opts["n"]);
try {
$queryString = $onlyNew ? "?new=1" : "";
$fileInfo = apiRequest("/{$dbType}/{$format}{$queryString}", $apiKey);
if ($onlyNew && !$fileInfo) {
vEcho("there are no new downloads available\n");
exit(0);
}
} catch (Exception $e) {
throw new Exception("cannot access download info : {$e->getMessage()}");
}
if (isset($opts["l"])) {
if (!isset($fileInfo)) {
vEcho("no download file match\n");
exit();
}
foreach ($fileInfo as $name => $value) {
echo "{$name}: {$value}\n";
}
exit();
}
if (isset($opts["z"])) {
$uncompress = true;
} else if (isset($opts["Z"]) || ($format === "csv")) {
$uncompress = false;
} else {
$uncompress = true;
}
$outputFile = "." . DIRECTORY_SEPARATOR . $fileInfo->name;
if (isset($opts["o"])) {
if (is_dir($opts["o"])) {
$outputFile = $opts["o"] . DIRECTORY_SEPARATOR . $fileInfo->name;
} else {
$outputFile = $opts["o"];
}
}
$sourcePrefix = $uncompress ? "compress.zlib://" : "";
if ($uncompress && preg_match('/\.gz$/i', $outputFile)) {
$outputFile = preg_replace('/\.gz$/i', '', $outputFile);
}
$outputTempFile = $outputFile . ".update-tmp";
if (file_exists($outputTempFile) && !unlink($outputTempFile)) {
throw new Exception("cannot delete temporary file {$outputTempFile}");
} else if (!isset($db) && file_exists($outputFile) && !isset($opts["w"])) {
throw new Exception("destination file {$outputFile} already exists, use -w to force overwrite");
}
vEcho("Starting update for {$dbType} ({$fileInfo->date})\n");
if (!copy($sourcePrefix . $fileInfo->url, $outputTempFile, stream_context_create([], [ "notification" => function($notificationCode, $severity, $message, $messageCode, $bytesTransferred, $bytesMax) {
static $totBytes, $prevPct = false;
if ($bytesMax) {
$totBytes = $bytesMax;
}
if ($bytesTransferred) {
if (isset($totBytes) && $totBytes) {
$pct = number_format(($bytesTransferred / $totBytes) * 100, 1);
}
if ($pct !== $prevPct) {
vEcho("\rDownloading: " . number_format($bytesTransferred / 1024) . " KB" . (isset($pct) ? " ({$pct}%)" : ""));
$prevPct = $pct;
}
}
}]))) {
throw new Exception("unable to download file to {$outputTempFile}");
}
vEcho("\rDownload completed: " . number_format(filesize($outputTempFile) / 1024, 1) . " KB\n");
$checkPrefix = $uncompress ? "" : "compress.zlib://";
if (isset($fileInfo->md5sum) || isset($fileInfo->sha1sum)) {
vEcho("Verify signature: ");
if (isset($fileInfo->md5sum)) {
$md5sum = md5_file($checkPrefix . $outputTempFile);
if ($md5sum !== $fileInfo->md5sum) {
vEcho("MISMATCH {$md5sum} != {$fileInfo->md5sum}\n");
throw new Exception("MD5 signature verification failed, file is probably corrupt or altered");
}
vEcho("[MD5] ");
}
if (isset($fileInfo->sha1sum)) {
$sha1sum = sha1_file($checkPrefix . $outputTempFile);
if ($sha1sum !== $fileInfo->sha1sum) {
vEcho("MISMATCH {$sha1sum} != {$fileInfo->sha1sum}\n");
throw new Exception("SHA1 signature verification failed, file is probably corrupt or altered");
}
vEcho("[SHA1] ");
}
vEcho("passed\n");
}
if (isset($db)) {
$dbip = new DBIP($db, $dbQuoteChar);
$relId = $dbType;
if ($fileInfo->version) {
$relId .= "-v{$fileInfo->version}";
}
switch ($relId) {
case "ip-to-country-lite": $importType = DBIP::TYPE_COUNTRY_LITE; break;
case "ip-to-city-lite": $importType = DBIP::TYPE_CITY_LITE; break;
case "ip-to-country-v4": $importType = DBIP::TYPE_COUNTRY_V4; break;
case "ip-to-location-v4": $importType = DBIP::TYPE_LOCATION_V4; break;
case "ip-to-isp-v4": $importType = DBIP::TYPE_ISP_V4; break;
case "ip-to-location-isp-v4":
case "ip-to-full-v4": $importType = DBIP::TYPE_FULL_V4; break;
case "ip-to-country-v3": $importType = DBIP::TYPE_COUNTRY_V3; break;
case "ip-to-location-v3": $importType = DBIP::TYPE_LOCATION_V3; break;
case "ip-to-isp-v3": $importType = DBIP::TYPE_ISP_V3; break;
case "ip-to-location-isp-v3":
case "ip-to-full-v3": $importType = DBIP::TYPE_FULL_V3; break;
case "ip-to-location-v2": $importType = DBIP::TYPE_LOCATION_V2; break;
case "ip-to-isp-v2": $importType = DBIP::TYPE_ISP_V2; break;
case "ip-to-location-isp-v2":
case "ip-to-full-v2": $importType = DBIP::TYPE_FULL_V2; break;
default: throw new Exception("unsupported database type");
}
if ($dbUseTempTable) {
$tempTable = "dbip_update_" . time();
$db->exec("drop table if exists {$dbQuoteChar}{$tempTable}{$dbQuoteChar}");
$db->exec("create table {$dbQuoteChar}{$tempTable}{$dbQuoteChar} like {$dbQuoteChar}{$dbTable}{$dbQuoteChar}");
} else {
$tempTable = $dbTable;
}
$dbip->importFromCsv($outputTempFile, $importType, $tempTable, function($numRows) use ($fileInfo) {
if ($numRows % 1000) {
return false;
}
if (isset($fileInfo->rows) && $fileInfo->rows) {
$pct = number_format(($numRows / $fileInfo->rows) * 100, 1);
}
vEcho("\rImporting: " . number_format($numRows) . " rows" . (isset($pct) ? " ({$pct}%)" : ""));
});
$numRows = (int)$db->query("select count(1) cnt from {$dbQuoteChar}{$tempTable}{$dbQuoteChar}")->fetchObject()->cnt;
if ($dbUseTempTable) {
$db->exec("drop table if exists {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}");
$db->exec("rename table {$dbQuoteChar}{$dbTable}{$dbQuoteChar} to {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}, {$dbQuoteChar}{$tempTable}{$dbQuoteChar} to {$dbQuoteChar}{$dbTable}{$dbQuoteChar}");
$db->exec("drop table {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}");
}
vEcho("\rDatabase updated: " . number_format($numRows) . " rows imported\n");
} else {
if (!rename($outputTempFile, $outputFile)) {
throw new Exception("cannot rename temporary file {$outputTempFile} to {$outputFile}");
}
vEcho("Wrote {$outputFile}\n");
}
} catch (Exception $e) {
if ($stdErr = @fopen("php://stderr", "w")) {
fwrite($stdErr, "ERROR: {$e->getMessage()}\n");
fclose($stdErr);
} else {
echo "ERROR: {$e->getMessage()}\n";
}
$exitCode = 1;
} finally {
if (isset($outputTempFile) && file_exists($outputTempFile)) {
unlink($outputTempFile);
}
if (isset($db) && isset($tempTable) && $dbUseTempTable) {
$db->exec("drop table if exists {$dbQuoteChar}{$tempTable}{$dbQuoteChar}");
$db->exec("drop table if exists {$dbQuoteChar}{$tempTable}_old{$dbQuoteChar}");
}
}
if ($exitCode) {
exit($exitCode);
}

346
app/Services/dbip/dbip.class.php Executable file
View file

@ -0,0 +1,346 @@
<?php
/**
*
* DB-IP.com database query and management class
*
* Copyright (C) 2022 db-ip.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
use PDO;
use Exception;
use PDOException;
class DBIPException extends Exception {
}
class DBIP {
const VERSION = 4;
const TYPE_COUNTRY_LITE = 1;
const TYPE_CITY_LITE = 2;
const TYPE_COUNTRY_V4 = 3;
const TYPE_LOCATION_V4 = 4;
const TYPE_ISP_V4 = 5;
const TYPE_FULL_V4 = 6;
const TYPE_COUNTRY_V3 = 7;
const TYPE_LOCATION_V3 = 8;
const TYPE_ISP_V3 = 9;
const TYPE_FULL_V3 = 10;
const TYPE_LOCATION_V2 = 11;
const TYPE_ISP_V2 = 12;
const TYPE_FULL_V2 = 13;
const TYPE_COUNTRY_IPINFO = 15;
const TYPE_COUNTRY = self::TYPE_COUNTRY_V4;
const TYPE_LOCATION = self::TYPE_LOCATION_V4;
const TYPE_ISP = self::TYPE_ISP_V4;
const TYPE_FULL = self::TYPE_FULL_V4;
private $db;
protected $dbQuoteChar = "";
public function __construct(PDO $db, $dbQuoteChar = "") {
$this->db = $db;
$this->db->setAttribute(PDO::ATTR_ERRMODE, PDO::ERRMODE_EXCEPTION);
$this->dbQuoteChar = $dbQuoteChar;
}
public function importFromCsv($fileName, $type, $tableName = "dbip_lookup", $progressCallback = null) {
switch ($type) {
case self::TYPE_COUNTRY_LITE:
$fields = array("ip_start", "ip_end", "country");
$fieldsprepare = $fields;
break;
case self::TYPE_COUNTRY_IPINFO:
$fields = array("ip_start", "ip_end", "country", "d1", "d2", "d3");
$fieldsprepare = array("ip_start", "ip_end", "country");
break;
case self::TYPE_CITY_LITE:
$fields = array("ip_start", "ip_end", "continent", "country", "stateprov", "city", "latitude", "longitude");
break;
case self::TYPE_COUNTRY_V4:
case self::TYPE_COUNTRY_V3:
$fields = array("ip_start", "ip_end", "continent", "country");
break;
case self::TYPE_LOCATION_V4:
$fields = array("ip_start", "ip_end", "continent", "country", "stateprov_code", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code");
break;
case self::TYPE_ISP_V4:
$fields = array("ip_start", "ip_end", "continent", "country", "isp_name", "as_number", "usage_type", "connection_type", "organization_name");
break;
case self::TYPE_FULL_V4:
$fields = array("ip_start", "ip_end", "continent", "country", "stateprov_code", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code", "isp_name", "as_number", "usage_type", "connection_type", "organization_name");
break;
case self::TYPE_LOCATION_V3:
$fields = array("ip_start", "ip_end", "continent", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code");
break;
case self::TYPE_ISP_V3:
$fields = array("ip_start", "ip_end", "continent", "country", "isp_name", "as_number", "connection_type", "organization_name");
break;
case self::TYPE_FULL_V3:
$fields = array("ip_start", "ip_end", "continent", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "weather_code", "isp_name", "as_number", "connection_type", "organization_name");
break;
case self::TYPE_LOCATION_V2:
$fields = array("ip_start", "ip_end", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name");
break;
case self::TYPE_ISP_V2:
$fields = array("ip_start", "ip_end", "country", "isp_name", "connection_type", "organization_name");
break;
case self::TYPE_FULL_V2:
$fields = array("ip_start", "ip_end", "country", "stateprov", "district", "city", "zipcode", "latitude", "longitude", "geoname_id", "timezone_offset", "timezone_name", "isp_name", "connection_type", "organization_name");
break;
default:
throw new DBIPException("invalid database type");
}
if (!file_exists($fileName)) {
throw new DBIPException("file {$fileName} does not exists");
}
$q = $this->prepareImport($tableName, $fieldsprepare);
if (preg_match('/\.gz(\..+)?$/', $fileName)) {
$openName = "compress.zlib://" . $fileName;
} else {
$openName = $fileName;
}
$f = @fopen($openName, "r");
if (!is_resource($f)) {
throw new DBIPException("cannot open {$fileName} for reading");
}
$nrecs = 0;
while ($r = fgetcsv($f, 1024, ",", '"', "\0")) {
foreach ($r as $k => $v) {
if (!isset($fields[$k])) {
throw new DBIPException("invalid CSV record for {$r[0]}");
}
switch ($fields[$k]) {
case "latitude":
case "longitude":
case "timezone_offset":
$r[$k] = (float)$v;
break;
case "d1":
case "d2":
case "d3":
unset($r[$k]);
break;
case "isp_name":
case "organization_name":
$r[$k] = mb_substr($v, 0, 128);
break;
case "city":
case "district":
case "stateprov":
$r[$k] = mb_substr($v, 0, 80);
break;
case "zipcode":
$r[$k] = mb_substr($v, 0, 20);
break;
case "timezone_name":
$r[$k] = mb_substr($v, 0, 64);
break;
case "connection_type":
case "stateprov_code":
case "usage_type":
case "geoname_id":
case "as_number":
if (!$r[$k]) $r[$k] = null;
break;
default:
}
}
try {
/*$r[] = self::addrType($r[0]);
$r[0] = inet_pton($r[0]);
$r[1] = inet_pton($r[1]);*/
$set = [
0 => inet_pton($r[0]),
1 => inet_pton($r[1]),
2 => $r[2],
3 => self::addrType($r[0])
];
$this->importRow($q, $set);
} catch (Exception $e) {
throw new Exception("cannot import record #{$nrecs}: {$e->getMessage()}");
}
if ((($nrecs % 100) === 0) && is_callable($progressCallback)) {
call_user_func($progressCallback, $nrecs);
}
$nrecs++;
}
fclose($f);
$this->finalizeImport();
return $nrecs;
}
public function lookup($addr, $tableName = "dbip_lookup") {
if ($ret = $this->doLookup($tableName, self::addrType($addr), inet_pton($addr))) {
$ret->ip_start = inet_ntop($ret->ip_start);
$ret->ip_end = inet_ntop($ret->ip_end);
return $ret;
} else {
throw new DBIPException("address not found");
}
}
protected function prepareImport($tableName, array $fields) {
try {
if ($this->db->query("select count(*) as cnt from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar}")->fetchObject()->cnt) {
throw new DBIPException("table {$tableName} is not empty");
}
$this->db->setAttribute(PDO::ATTR_EMULATE_PREPARES, false);
$this->db->beginTransaction();
$q = $this->db->prepare("insert into {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} (" . implode(",", $fields) . ",addr_type) values (" . implode(",", array_fill(0, count($fields), "?")) . ",?)");
return $q;
} catch (PDOException $e) {
throw new DBIPException("database error: {$e->getMessage()}");
}
}
protected function finalizeImport() {
try{
$this->db->commit();
}catch (Exception $e) {
throw new Exception("commit import record: {$e->getMessage()}");
}
}
protected function importRow($res, $row) {
return $res->execute($row);
}
protected function doLookup($tableName, $addrType, $addrStart) {
$q = $this->db->prepare("select * from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} where addr_type = ? and ip_start <= ? order by ip_start desc limit 1");
$q->execute(array($addrType, $addrStart));
return $q->fetchObject();
}
static private function addrType($addr) {
if (ip2long($addr) !== false) {
return "ipv4";
} else if (preg_match('/^[0-9a-fA-F:]+$/', $addr) && @inet_pton($addr)) {
return "ipv6";
}
throw new DBIPException("unknown address type for {$addr}");
}
}
/**
* DBIP MySQL class
*
* If you are using a MySQL database backend, please prefer the DBIP base class which uses the PDO mysql driver.
* This is only meant to be used on PHP installations where PDO is disabled and the old mysql_* interface is available.
*/
class DBIPMySQL extends DBIP {
private $db;
public function __construct($db) {
$this->db = $db;
}
protected function prepareImport($tableName, array $fields) {
$q = mysql_query("select count(*) as cnt from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar}", $this->db);
$r = mysql_fetch_object($q);
mysql_free_result($q);
if ($r->cnt) {
throw new DBIPException("table {$tableName} is not empty");
}
return array($tableName, $fields);
}
protected function finalizeImport() {
}
protected function importRow($res, $row) {
$vals = array();
foreach ($row as $val) {
$vals[] = "'" . mysql_real_escape_string($val) . "'";
}
if (!mysql_query("insert into {$this->dbQuoteChar}{$res[0]}{$this->dbQuoteChar} (" . implode(",", $res[1]) . ",addr_type) values (" . implode(",", $vals) . ")", $this->db)) {
throw new DBIPException("database error: cannot insert row");
}
return true;
}
protected function doLookup($tableName, $addrType, $addrStart) {
$q = mysql_query("select * from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} where addr_type = '{$addrType}' and ip_start <= '" . mysql_real_escape_string($addrStart) . "' order by ip_start desc limit 1", $this->db);
$r = mysql_fetch_object($q);
mysql_free_result($q);
return $r;
}
}
/**
* DBIP MySQLI class
*
* If you are using a MySQL database backend, please prefer the DBIP base class which uses the PDO mysql driver.
* This is only meant to be used on PHP installations where PDO is disabled and the old mysqli_* interface is available.
*/
class DBIPMySQLI extends DBIP {
private $db;
public function __construct($db) {
$this->db = $db;
}
protected function prepareImport($tableName, array $fields) {
$q = mysqli_query($this->db, "select count(*) as cnt from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar}");
$r = mysqli_fetch_object($q);
mysqli_free_result($q);
if ($r->cnt) {
throw new DBIPException("table {$tableName} is not empty");
}
return array($tableName, $fields);
}
protected function finalizeImport() {
}
protected function importRow($res, $row) {
$vals = array();
foreach ($row as $val) {
$vals[] = "'" . mysqli_real_escape_string($this->db, $val) . "'";
}
if (!mysqli_query($this->db, "insert into {$this->dbQuoteChar}{$res[0]}{$this->dbQuoteChar} (" . implode(",", $res[1]) . ",addr_type) values (" . implode(",", $vals) . ")")) {
throw new DBIPException("database error: cannot insert row");
}
return true;
}
protected function doLookup($tableName, $addrType, $addrStart) {
$q = mysqli_query($this->db, "select * from {$this->dbQuoteChar}{$tableName}{$this->dbQuoteChar} where addr_type = '{$addrType}' and ip_start <= '" . mysqli_real_escape_string($this->db, $addrStart) . "' order by ip_start desc limit 1");
$r = mysqli_fetch_object($q);
mysqli_free_result($q);
return $r;
}
}

96
app/Services/dbip/import.php Executable file
View file

@ -0,0 +1,96 @@
#!/usr/bin/env php
<?php
/**
*
* DB-IP.com database import script
*
* Copyright (C) 2018 db-ip.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
require "dbip.class.php";
$opts = getopt("f:d:t:b:u:p:");
$filename = @$opts["f"];
$type = @$opts["d"];
$dbname = @$opts["b"]
or $dbname = "mivita";
$table = @$opts["t"]
or $table = "dbip_lookup_2"; //
$username = @$opts["u"]
or $username = "kadmin";
$password = @$opts["p"]
or $password = "KT32vQ7ix";
$host = "192.168.1.8";
//https://db-ip.com/db/download/ip-to-country-lite
$filename = "dbip-country-lite-2024-07.csv";
$table = "dbip_lookup";
//https://ipinfo.io/account/data-downloads
$filename = "dbip-country-ipinfo-2024.csv";
$table = "dbip_lookup_2";
if (!isset($type) && preg_match('/dbip-(country-lite|country-ipinfo|city-lite|country|location|isp|full)/i', $filename, $res)) {
$type = $res[1];
}
if (!isset($filename) || !isset($type)) {
die("usage: {$argv[0]} -f <filename.csv[.gz]> [-d <country-lite|city-lite|country|location|isp|full>] [-b <database_name>] [-t <table_name>] [-u <username>] [-p <password>]\n");
}
switch (strtolower($type)) {
case "country-lite": $dbtype = DBIP::TYPE_COUNTRY_LITE; break;
case "country-ipinfo": $dbtype = DBIP::TYPE_COUNTRY_IPINFO; break;
case "city-lite": $dbtype = DBIP::TYPE_CITY_LITE; break;
case "country": $dbtype = DBIP::TYPE_COUNTRY; break;
case "location": $dbtype = DBIP::TYPE_LOCATION; break;
case "isp": $dbtype = DBIP::TYPE_ISP; break;
case "full": $dbtype = DBIP::TYPE_FULL; break;
default: echo "invalid database type\n"; exit(1);
}
try {
// Connect to the database
$db = new PDO("mysql:{$host}=localhost;dbname={$dbname};charset=utf8mb4", $username, $password);
// Alternatively connect to MySQL using the old interface
// Comment the PDO statement above and uncomment the mysql_ calls
// below if your PHP installation doesn't support PDO :
// $db = mysql_connect("localhost", $username, $password);
// mysql_select_db($dbname, $db);
// Instanciate a new DBIP object with the database connection
$dbip = new DBIP($db); //DBIPMySQLI
// Alternatively instanciate a DBIP_MySQL object
// Comment the new statement above and uncomment below if your PHP
// installation doesn't support PDO :
// $dbip = new DBIPMySQL($db);
$nrecs = $dbip->importFromCsv($filename, $dbtype, $table, function($progress) {
echo "\r{$progress} ...";
});
echo "\rfinished importing " . number_format($nrecs) . " records\n";
} catch (DBIPException $e) {
echo "error: {$e->getMessage()}\n";
}

View file

@ -0,0 +1,73 @@
#!/usr/bin/env php
<?php
/**
*
* DB-IP.com database sample query code
*
* Copyright (C) 2018 db-ip.com
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
*/
// Include the DB-IP class
require "dbip.class.php";
$host = "192.168.1.8";
$dbname = "mivita";
$username = "kadmin";
$password = "KT32vQ7ix";
$table = "dbip_lookup";
$table_2 = "dbip_lookup_2";
try {
// Check if we have a command line parameter
if ($argc < 2) {
die("usage: {$argv[0]} <ip_address>\n");
}
// Connect to the database
$db = new PDO("mysql:{$host}=localhost;dbname={$dbname};charset=utf8mb4", $username, $password);
// Alternatively connect to MySQL using the old interface
// Comment the PDO statement above and uncomment the mysql_ calls
// below if your PHP installation doesn't support PDO :
// $db = mysql_connect("localhost", "root", "");
// mysql_select_db("test", $db);
// Instanciate a new DBIP object with the database connection
$dbip = new DBIP($db);
// Alternatively instanciate a DBIP_MySQL object
// Comment the new statement above and uncomment below if your PHP
// installation doesn't support PDO :
// $dbip = new DBIPMySQL($db);
// Lookup an IP address
$inf = $dbip->lookup($argv[1], $table);
// Show the associated country
echo "t:".$table." country = " . $inf->country . "\n";
$inf = $dbip->lookup($argv[1], $table_2);
// Show the associated country
echo "t:".$table_2." country = " . $inf->country . "\n";
} catch (DBIPException $e) {
echo "error: {$e->getMessage()}\n";
exit(1);
}