2017-04-13 12 views
1

私はyii2を使用しています。 getFreeIPAddressメソッドで使用されていない(データベースにない)IPを見つける必要があります。私はこのようなクラスを持っている:無料のIPアドレスを取得するアルゴリズム

class Radreply extends ActiveRecord { 

    const ATTRIBUTE_DEFAULT_IP_ADDRESS = 'Framed-IP-Address'; 

    const IP_ADDRESS_MAX = '10.255.255.255'; // max value for IP 
    const IP_ADDRESS_MIN = '10.0.0.11';  // min value for IP 

    public function getIntegerIP(){ // converts IP from string to integer format 
     return ip2long($this->value); 
    } 

    public static function getFreeIPAddress(){ 
     $records = self::findAll(['attribute'=>self::ATTRIBUTE_DEFAULT_IP_ADDRESS]); // get all record which contain IP address 
     $existIPs = ArrayHelper::getColumn($records,'integerIP'); // get array of IP which is converted to integer by method getIntegerIP 

     for ($integerIP = ip2long(self::IP_ADDRESS_MIN); $integerIP<=ip2long(self::IP_ADDRESS_MAX); $integerIP++){ 
     // increasing one by one IP address in integer format from value IP_ADDRESS_MIN to value IP_ADDRESS_MAX 

      if (!in_array($integerIP, $existIPs)){ 
       $stringIP = long2ip($integerIP); 
       $arrayDigits = explode('.', $stringIP); 
       $lastDigit = array_pop($arrayDigits); 

       if ($lastDigit!='0'){ // check if last digit of IP is not 0 
        return $stringIP; 
       } 

      } 

     } 
     return ''; 
    } 
} 

方法getFreeIPAddressの作品が見つかりますが、DB内のIPを持つレコードの多くと1 IPずつ増加し、このIPがDBに存在するかどうかをチェックするには、非常に長い道のりがあります。どのように私はこのアルゴリズムを最適化できますか?未使用のIPを取得する方法はありますか?

+0

データベース内の余分なテーブルのないよりよい解決策を見つけた、と思います利用可能なすべてのIPアドレスのテーブルを作ってから、あなたの他のテーブルに対して右の結合をして、無料のIPアドレスのリストを入手してください。 – cmorrissey

+0

@ cmorrisseyは良い考えに感謝します。しかし、私は利用可能なIPアドレスの範囲を変更したい場合は問題になります、私は毎回新しいテーブルを作成する必要があります。また、この表は非常に大きくなります:min - 10.0.0.11 '、max - '10 .255.255.255'(16777 204 records) –

+1

大丈夫私はあなたのために新しい考えを持っています...データベース内の行数をIPアドレスの範囲内で数えて、次の範囲に移動しない場合に使用可能なIPアドレスがあるかどうかを確認します。これにより、範囲を再帰的に絞り込むことができます。これは非常に基本的な検索機能ですが、指数関数的に検索を高速化する必要があります。 – cmorrissey

答えて

2

私は私はあなたができたummmm

class Radreply extends ActiveRecord { 

    const ATTRIBUTE_DEFAULT_IP_ADDRESS = 'Framed-IP-Address'; 

    const IP_ADDRESS_MAX = '10.255.255.255'; // max value for IP 
    const IP_ADDRESS_MIN = '10.0.0.11';  // min value for IP 

    public function getIntegerIP(){ // converts IP from string to integer format 
     return ip2long($this->value); 
    } 

    public static function getFreeIPAddress(){ 
     $records = self::findAll(['attribute'=>self::ATTRIBUTE_DEFAULT_IP_ADDRESS]); // gets all record which contain IP address 
     $existIPs = ArrayHelper::getColumn($records,'integerIP'); // gets array of IP which is converted to integer by method getIntegerIP 

     $intIpAddressMin = ip2long(self::IP_ADDRESS_MIN);  // gets min IP in integer format 
     $endRange = empty($existIPs) ? $intIpAddressMin : max($existIPs); // checks if at least one IP is used 
     $availableIPs = range($intIpAddressMin, $endRange + 2); // generates array with available IP addresses (+2 because next address can be with last digit 0) 
     $missingIPs = array_diff($availableIPs,$existIPs); // removes all used IP 

     foreach ($missingIPs as $value){ 
      $lastDigit = $value % 256; 
      if ($lastDigit != 0){ 
       return long2ip($value); 
      } 
     } 
     return ''; 
    } 
} 
0

するbool in_array(混合$針、配列$干し草の山[、ブール$厳しい= FALSE])私の意見で

、あなたは厳しい真を設定することができます。

厳密= falseを

<?php                                        

$y="1800"; 
$x = array(); 
for($j=0;$j<50000;$j++){ 
     $x[]= "{$j}"; 
} 

for($i=0;$i<30000;$i++){ 
    if(in_array($y,$x)){ 
      continue; 
    } 
    } 

時間のphp test.phpを

real 0m4.418s 
user 0m4.404s 
sys 0m0.012s 

厳密には

for($i=0;$i<30000;$i++){ 
    if(in_array($y,$x ,true)){ 
       continue; 
     } 
} 

時間のphp test.phpをあると私のPHPコード

real 0m1.548s 
user 0m1.540s 
sys 0m0.004s 

さらに、使用したIPを昇順で取得できる場合はどうなりますか? o(m + n)時間複雑度、mは試すべきipの長さ、nbはすべてマージアルゴリズムのdb内のすべてのIPの長さです。

あなたは昇順擬似コードで

で使用するIPアドレスを取得することができます。

tmpIp = minIp; 
while(temIp <= maxIp){ 
     if(dbIsEmpty){ 
      break; 
     } 
      dbIp =getNextFromDb(); 

     while(temIp < dbIp){ 
     printf temIp ; 
     temIp ++; 
     } 
     temIp ++; 
} 
while(temIp <= maxIp){ 
    printf temIp ; 
    temIp++; 
} 

ここで私は$カウント++によるエコーIPをrepalce私のPHPコードは、あります。このデモで 長いそれは10秒ほどかかる

<?php                                               
    function mergeSort($result){ 
    $minIp = ip2long('10.0.0.11') ; 
    $maxIp = ip2long('10.255.255.255'); 



    $count =0; 
    $tmpIp = $minIp; 
    while($temIp <= $maxIp){ 
     if(empty($result)){ 
     break ; 
    } 
    $tmp = array_pop($result); 
    $dbIp =$tmp['ip']; 

     while($temIp < $dbIp){ 
     // echo temIp ; 
     // i repalce it by count ++ , i don't want it 
     //full my teminal . 
     $count ++; 
     $temIp ++; 
     } 
     $temIp ++; 


    } 
    while($temIp <= $maxIp){ 
     //echo $temIp ; replace by $count++ 
     $count ++; 
     $temIp++; 
    } 
    return $count -1; 

} 

$servername = "localhost"; 
$username = "root"; 
$password = "aaaaa"; 
$dbname = "IP"; 

$conn = new PDO('mysql:host=' . $servername . ';dbname=' . $dbname , $username, $password); 
$conn->setAttribute(PDO::ATTR_AUTOCOMMIT , true); 
$stmt = $conn->prepare("select * from ipTable order by ip desc"); 
    $stmt->execute(); 
    $result = $stmt->fetchAll(); 
    $count = mergeSort($result); 
    echo $count ; 
    ?> 

のタイプで約80000 IPがあります。 時間のphp test.phpを本当0m10.626s ユーザー0m10.416s のsys 0m0.168s

+0

答えに感謝します。 「マージアルゴリズム」とはどういう意味ですか? –

+0

@RomanYakoviv https://en.wikipedia.org/wiki/Merge_algorithm#Merging_two_lists –

+0

私は、あなたが使用していないipを望んでいたり、未使用のipを一度入手したりするという問題がありますか? –

関連する問題