IPによってプロバイダーを決定する方法

問題の説明は非常に簡単です。ユーザーのIPアドレスによってプロバイダーを決定する必要があります。 その後、このデータを分析システムで使用する必要があります。また、GoogleやRipeなどのデータと比較することもできなければなりません。



この記事で提供されるコードは完全ではないことをすぐに言わなければなりません。 使用されるプログラミング言語はPHPです(もちろん、このようなタスクにはCまたはPerlを使用することをお勧めします)。 データベース-MySQL(ここでは、高速で多数の選択を処理できるデータベースを選択することをお勧めします。たとえば、Tarantool)。 しかし、日常生活では、これらのテクノロジー/言語で十分です。



データベースを検索し、そこからデータを抽出します



それでは始めましょう。 プロバイダーのデータはどこで入手できますか? RIPEサービスはすぐに選択されました。 欠点は、データベース全体がテキストファイルに保存されることです 。 しばらくの間、「グーグルで」MySQL用のコンバーターが見つかりませんでした。 まあ、それはタスクを少し複雑にしました。 しかし、それは問題ではありません。有名なビデオクリップとそのフレーズを思い出してください:「あなたはエキスパートです」。データベースファイルの説明を探し、MySQLでテキスト形式からデータパーサーを書くことにしました。



しかし、少し待ち伏せがありました。 フィールドの説明はありますが、テーブル間の関係が見つかりませんでした(もちろん、見栄えが悪いかもしれません)。 しかし、これはすでにかなり具体的な問題になっています。



さらに、私は間違った方向に考え始め、何とかその場でファイルのフィールドを一致させようとしました。 つまり、1つのファイルを解析するスクリプトを実行しました(これは非常に「松葉杖」のように覚えています。休日、酔ってしまい、何も覚えていません。翌日、友人はポーチで裸で走り、わいせつな叫び声を上げました。あなたはひどく恥ずかしいです)。



その結果、数時間後(はい、数時間後)、何もしていないことに気付き、すべてのデータをMySQLに格納することにしました。 幸いなことに、データを調査する過程で、比較に必要なフィールドを理解することができました。



データベースにデータをインポートする



フィールドがわかっているため、次のテーブルを作成しました。



CREATE TABLE `test_inetnum` ( `sip` bigint(20) unsigned NOT NULL, `eip` bigint(20) unsigned NOT NULL, `org` varchar(255) NOT NULL, PRIMARY KEY (`sip`,`eip`), KEY `idx_org` (`org`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `test_organization` ( `organisation` varchar(255) NOT NULL, `org-name` varchar(255) NOT NULL, PRIMARY KEY (`organisation`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `test_route` ( `sip` bigint(20) unsigned NOT NULL, `eip` bigint(20) unsigned NOT NULL, `origin` varchar(255) NOT NULL, PRIMARY KEY (`sip`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8; CREATE TABLE `test_aut_num` ( `aut-num` varchar(255) NOT NULL, `org` varchar(255) NOT NULL, PRIMARY KEY (`aut-num`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      





sipおよびeipテーブルのフィールドは、範囲の先頭と末尾のip2longでデコードされたIPアドレスです。



データを解析するためのクラス:



 <?php namespace Ripe; class Ripe { /** * @var string -      RIPE */ public $folder; /** * @var int - ,   */ public $time = 86400; /** * Ripe constructor. * * @param string $folder */ function __construct($folder = '') { if (empty($folder)) { $folder = __DIR__ . '/../../config/ripe'; } if (!is_dir(__DIR__ . '/../../config/ripe')) { mkdir(__DIR__ . '/../../config/ripe', 0777, true); } $this->folder = $folder; } /** *    . * * @param string $file * * @return bool */ function needUpdate($file = '') { $current = time(); if ($current - filectime($this->folder . '/' . $file) > $this->time) { return true; } return false; } /** *  . * * @param string $url */ function download($url = '') { if (!empty($url) && true === $this->needUpdate($url) ) { system("cd " . realpath($this->folder) . " && wget ftp://ftp.ripe.net/ripe/dbase/split/" . $url . " && gunzip $url"); } } /** *    . * * @param string $file * @param $callback */ function read($file = '', $callback) { if (is_file($this->folder . '/' . $file)) { $f = fopen($this->folder . '/' . $file, 'r'); if (!empty($f)) { $string = []; while (($buffer = fgets($f)) !== false) { //   if ("\n" != $buffer) { $string[] = trim($buffer); } else { $blockArray = []; //     for ($i = 0; $i < $ic = count($string); $i++) { if (strpos($string[$i], ': ') === false) { break; } else { $arBlockData = explode(": ", $string[$i]); if (!empty($arBlockData)) { $key = trim($arBlockData[0]); $value = trim($arBlockData[1]); if (!empty($blockArray[$key])) { $blockArray[$key] .= $value . "\n"; } else { $blockArray[$key] = $value; } } } } // callback if (!empty($callback) && is_callable($callback) && !empty($blockArray) ) { call_user_func_array($callback, [ $blockArray, $file ]); } $string = ''; } } } } } }
      
      





データをブロックに書き込みます。つまり、ブロックを受け取り、すぐに書き留めました。 パフォーマンスを向上させるには、バッチでデータを挿入することをお勧めします。 組織データベースにダウンロードして書き込むためのコードは次のようになります。



 $ripe->download('ripe.db.organisation.gz'); $ripe->read('ripe.db.organisation', function ($block, $file) { $ripeRoute = new \Ripe\RipeOrganization(); $ripeRoute->save($block); });
      
      





テーブル内のフィールドは、ファイル内と同じキーで入力されます。 フィールドを変更する必要がある場合、saveメソッドには「挿入前」ハンドラーがあり、これを使用してフィールドの名前を変更し、変更したものに書き込むことができます。



データ分析とサマリー表の取得。



データが受信されたので、判定自体がすでに合格するサマリーテーブルを作成できます。



 CREATE TABLE `test_ripe` ( `sip` bigint(20) unsigned NOT NULL, `eip` bigint(20) unsigned NOT NULL, `org_code` varchar(100) NOT NULL, `org_name` varchar(255) NOT NULL, PRIMARY KEY (`sip`,`eip`), KEY `idx_org_name` (`org_name`) ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
      
      





今、最も簡単なことは残っています-必要なデータをファイナルテーブルに転送することです。



すべては、いくつかのリクエストによって決定されます。



 select * from test_inetnum as t1 inner join test_organization as t2 on t1.org = t2.organisation; select * from test_route as t1 inner join test_aut_num as t2 on t1.origin = t2.`aut-num` inner join test_organization as t3 on t2.org = t3.organisation;
      
      





取得したデータはテーブルtest_ripeに入れられ、幸福になります。



結果



結果は私の期待を上回りました。 プロバイダーの定義は非常に正確に機能します(アドレスプールでテスト済み)。 また、素敵なボーナスは、 2ipよりもこのベースで定義がうまく機能することです



さて、実際には、次のクエリを使用して現在のテーブルからプロバイダーを決定できます。



 SELECT * FROM `test_ripe` WHERE `sip` <= '33554435' AND `eip` >= '33554435' ORDER BY `eip` DESC LIMIT 1
      
      





ある範囲が別の範囲に含まれることが発生するため、リクエストのソートが必要です。



All Articles