Changeset View
Changeset View
Standalone View
Standalone View
src/app/Console/Commands/UpdateIP4NetsCommand.php
- This file was added.
<?php | |||||
namespace App\Console\Commands; | |||||
use Carbon\Carbon; | |||||
use Illuminate\Console\Command; | |||||
class UpdateIP4NetsCommand extends Command | |||||
{ | |||||
machniak: UpdateIp4NetsComand -> UpdateIp4Nets, here and in filename. | |||||
/** | |||||
* The name and signature of the console command. | |||||
* | |||||
* @var string | |||||
*/ | |||||
protected $signature = 'update:ip4nets'; | |||||
Not Done Inline ActionsI'd like it to be "data:ip4nets", for consistency with "data:countries". Or make update:countries, if you really prefer "update:" prefix. Also, I'm not sure how useful this would be but we could have php artisan data:ip4nets {ip} to see/test the resolution. machniak: I'd like it to be "data:ip4nets", for consistency with "data:countries". Or make update… | |||||
/** | |||||
* The console command description. | |||||
* | |||||
* @var string | |||||
*/ | |||||
protected $description = 'Update IP4 Networks'; | |||||
/** | |||||
* Create a new command instance. | |||||
* | |||||
* @return void | |||||
*/ | |||||
public function __construct() | |||||
{ | |||||
parent::__construct(); | |||||
} | |||||
/** | |||||
* Execute the console command. | |||||
* | |||||
* @return int | |||||
*/ | |||||
public function handle() | |||||
{ | |||||
$rirs = [ | |||||
'afrinic' => 'ftp://ftp.afrinic.net/stats/afrinic/delegated-afrinic-latest', | |||||
'apnic' => 'ftp://ftp.apnic.net/pub/apnic/stats/apnic/delegated-apnic-latest', | |||||
'arin' => 'ftp://ftp.arin.net/pub/stats/arin/delegated-arin-extended-latest', | |||||
'lacnic' => 'ftp://ftp.lacnic.net/pub/stats/lacnic/delegated-lacnic-latest', | |||||
'ripencc' => 'ftp://ftp.ripe.net/ripe/stats/delegated-ripencc-latest' | |||||
]; | |||||
$today = Carbon::now()->toDateString(); | |||||
foreach ($rirs as $rir => $url) { | |||||
$file = storage_path("{$rir}-{$today}"); | |||||
if (!is_file($file)) { | |||||
$fp = fopen(storage_path("{$rir}-{$today}"), 'w'); | |||||
$curl = curl_init(); | |||||
curl_setopt($curl, CURLOPT_URL, $url); | |||||
Not Done Inline Actions
This should fix both: if (!is_file($file)) { $content = file_get_contents($url); // This throws errors on failure if ($content) { file_put_contents($file, $content); } } machniak: 1. A nicer error handling when the request fails. Right now the only error I see is "Unable to… | |||||
Done Inline ActionsI'm not sure how to capture curl errors to be honest. I believe the curl version does not assign the contents of the file obtained to memory but instead passes through the downloaded information directly to the file descriptor. The file size here is some 10 megabytes at times -- but could be up to 20 megabytes. vanmeeuwen: I'm not sure how to capture curl errors to be honest.
I believe the curl version does not… | |||||
curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1); | |||||
curl_setopt($curl, CURLOPT_FILE, $fp); | |||||
curl_exec($curl); | |||||
curl_close($curl); | |||||
fclose($fp); | |||||
} | |||||
$serial = $this->serialFromStatsFile($file); | |||||
$numLines = $this->countLines($file); | |||||
$bar = \App\Utils::createProgressBar( | |||||
$this->output, | |||||
$numLines, | |||||
"Importing IPv4 Networks from {$file}" | |||||
); | |||||
$fp = fopen($file, 'r'); | |||||
$nets = []; | |||||
while (!feof($fp)) { | |||||
$line = trim(fgets($fp)); | |||||
if ($line == "") { | |||||
continue; | |||||
} | |||||
if ((int)$line) { | |||||
continue; | |||||
} | |||||
if ($line[0] == "#") { | |||||
continue; | |||||
} | |||||
$items = explode('|', $line); | |||||
if (sizeof($items) < 7) { | |||||
continue; | |||||
} | |||||
if ($items[1] == "*") { | |||||
continue; | |||||
} | |||||
if ($items[2] != "ipv4") { | |||||
continue; | |||||
} | |||||
if ($items[5] == "00000000") { | |||||
$items[5] = "19700102"; | |||||
} | |||||
if ($items[1] == "" || $items[1] == "ZZ") { | |||||
continue; | |||||
} | |||||
$bar->advance(); | |||||
$mask = 32 - log($items[4], 2); | |||||
$net = \App\IP4Net::where( | |||||
[ | |||||
'net_number' => $items[3], | |||||
'net_mask' => $mask, | |||||
'net_broadcast' => long2ip((ip2long($items[3]) + 2 ** (32 - $mask)) - 1) | |||||
] | |||||
)->first(); | |||||
if ($net) { | |||||
$net->update( | |||||
[ | |||||
'country' => $items[1], | |||||
'serial' => $serial | |||||
] | |||||
); | |||||
continue; | |||||
} | |||||
$nets[] = [ | |||||
'net_number' => $items[3], | |||||
'net_mask' => $mask, | |||||
'net_broadcast' => long2ip((ip2long($items[3]) + 2 ** (32 - $mask)) - 1), | |||||
'country' => $items[1], | |||||
'serial' => $serial | |||||
]; | |||||
if (sizeof($nets) >= 100) { | |||||
\App\IP4Net::insert($nets); | |||||
$nets = []; | |||||
} | |||||
} | |||||
if (sizeof($nets) > 0) { | |||||
\App\IP4Net::insert($nets); | |||||
} | |||||
$bar->finish(); | |||||
$this->info("DONE"); | |||||
} | |||||
} | |||||
private function countLines($file) | |||||
{ | |||||
$numLines = 0; | |||||
$fh = fopen($file, 'r'); | |||||
while (!feof($fh)) { | |||||
$line = trim(fgets($fh)); | |||||
$items = explode('|', $line); | |||||
if (sizeof($items) < 3) { | |||||
continue; | |||||
} | |||||
if ($items[2] == "ipv4") { | |||||
$numLines++; | |||||
} | |||||
} | |||||
fclose($fh); | |||||
return $numLines; | |||||
} | |||||
private function serialFromStatsFile($file) | |||||
{ | |||||
$serial = null; | |||||
$fh = fopen($file, 'r'); | |||||
while (!feof($fh)) { | |||||
$line = trim(fgets($fh)); | |||||
$items = explode('|', $line); | |||||
if (sizeof($items) < 2) { | |||||
continue; | |||||
} | |||||
if ((int)$items[2]) { | |||||
$serial = (int)$items[2]; | |||||
break; | |||||
} | |||||
} | |||||
fclose($fh); | |||||
return $serial; | |||||
} | |||||
} |
UpdateIp4NetsComand -> UpdateIp4Nets, here and in filename.