16


15

私は効率的な方法でMySQL 5.0にIPv6アドレスを保存しようとしています。 私はこれに関連する他の質問、https://stackoverflow.com/questions/420680/how-to-store-ipv6-compatible-address-in-a-relational-database [このような]を読んだことがあります。 その質問の著者は、最終的に2つのBIGINTフィールドを選びました。 私の検索では、よく使われる別のメカニズムも明らかになっています。DIPIMAL(39,0)を使ってIPv6アドレスを保存する方法です。 それについて2つ質問があります。

  1. 2 * BIGINTなどの他の方法に比べてDECIMAL(39,0)を使用することの利点と欠点は何ですか?

  2. inet_pton()で返されるバイナリ形式から(PHPで)どのようにしてMySQLで使用可能な10進文字列形式に変換するのですかinet_ntop()で-print?

3 Answer


30


代わりに VARBINARY(16)`コラムに行き、http://man7.org/linux/man-pages/man3/inet_pton.3.html [`inet_pton()]とhttp://man7.orgを使います/linux/man-pages/man3/inet_ntop.3.html [inet_ntop()]を使って変換します。

これらの関数は実行中のMySQLサーバーにロードすることができ、IPv4でよく知られている INET_NTOA`と INET_ATON`関数のように、SQLで INET6_NTOP`と INET6_PTON`を提供します。

編集:現在MySQLには互換性のある関数があり、http://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_inet6-aton [異なる] http://dev.mysqlだけです。 com / doc / refman / 5.7 / ja / miscellaneous-functions.html#function_inet6-ntoa [名前]。 あなたが5.6より前のMySQLを使用していて、便利な将来のアップグレードパスを探しているなら、上記を使用してください。


19


これは私が今からIPアドレスをDECIMAL(39,0)フォーマットに変換するのに使う関数です。 それらは "presentation-to-decimal"と "decimal-to-presentation"のためにinet_ptodとinet_dtopと名付けられています。 PHPではIPv6とbcmathのサポートが必要です。

/ **
 *  IPアドレスを表示からMySQL *での保存に適した10進数(39,0)形式に変換します。
 *  @param string $ ip_address IPv4、IPv6、または10進表記のIPアドレス
 *  @return文字列10進表記のIPアドレス* / function inet_ptod($ ip_address){// IPv4アドレスif(strpos($ ip_address、 ':')=== false $ ip_address; }

// IPv6アドレスif(strpos($ ip_address、 ':')!== false){$ network = inet_pton($ ip_address);} $ parts = unpack( 'N *'、$ network);

foreach($部分として

if(!is_string($ part)){$ part =(文字列)$ part; }}

$ decimal = $ parts [4]; $ decimal = bcadd($ decimal、bcmul($ parts [3]、 '4294967296')); $ decimal = bcadd($ decimal、bcmul($ parts [2]、 '18446744073709551616')); $ decimal = bcadd($ decimal、bcmul($ parts [1]、 '79228162514264337593543950336'));

$ decimalを返します。 }

// 10進アドレスreturn $ ip_address; }

/ **
 *  IPアドレスを10進形式から表示形式に変換する*
 *  @param string $ decimal IPv4、IPv6、または10進表記のIPアドレス
 *  @return string表示形式のIPアドレス* / function inet_dtop($ decimal){// if(strpos($ decimal、 ':')!== false || strpos($ decimal、 '。') !== false){$ decimalを返す。 }

// 10進数形式$ parts = array(); $ parts [1] = bcdiv(​​$ decimal、 '79228162514264337593543950336'、0); $ decimal = bcsub($ decimal、bcmul($ parts [1]、 '79228162514264337593543950336')); $ parts [2] = bcdiv(​​$ decimal、 '18446744073709551616'、0); $ decimal = bcsub($ decimal、bcmul($ parts [2]、 '18446744073709551616')); $ parts [3] = bcdiv(​​$ decimal、 '4294967296'、0); $ decimal = bcsub($ decimal、bcmul($ parts [3]、 '4294967296')); $ parts [4] = $ decimal;

foreach($部分として

$ part =(int)$ part; }

$ network = pack( 'N4'、$ parts [1]、$ parts [2]、$ parts [3]、$ parts [4]); $ ip_address = inet_ntop($ network);

// if(preg_match( '/ ^ :: \ d。\ d。\ d。\ d $ /'、$ ip_address)){return substr($ ip_address、2); }

$ ip_addressを返します。 }


0


  • 10進数(39)*

長所:

  • 基本的な算術演算子(andなど)と共に機能します。

  • 基本索引付け(完全または範囲)で機能します。

  • フォーマットはディスプレイにやさしいです。

短所:

  • IPv6の範囲外の値を受け入れることができます。

  • 非常に効率的なストレージメカニズムではありません。

  • どの数学演算子または関数が機能し、どれが機能しないかについて混乱を引き起こす可能性があります。

  • BINARY(16)…​ *

長所:

  • 正確な表現のための最も効率的なフォーマット

  • 基本索引付け(正確および範囲)で機能します。

  • 8ビットの倍数であるプレフィックスのプレフィックスインデックスで機能します。

  • 有効なIPv6値のみを格納します(ただし、有効なアドレス指定を保証するものではありません)。

  • それ以降のバージョンのMySQLには、IPv6形式との間のこの形式の変換をサポートする機能があります(4in6は不可)。

短所:

  • 表示には向いていません。

  • 数値用の演算子や関数には向いていません。

  • BINARY(39)…​ *

これはフルアドレス用です(4in6でもhexdecを使用)。 バイナリではなくASCIIにすることもできます。

長所:

  • 人間が読むことができる(あなたがIPv6と呼べるのなら)。

  • 基本的な索引付け(正確および範囲)をサポートします。

  • 4ビットの倍数のプレフィックスインデックスをサポートします。

  • 直接IPv6互換です。 変換は不要です。

短所:

  • 数学関数や演算子ではうまく機能しません。

  • 最も非効率的なストレージ

  • 無効な表現を許可できます。

奇数:

  • 大文字と小文字を区別しないなどのことが必要な場合は、複雑になります。

  • IPv6には他の表示形式がありますが、これらを使用すると、同じアドレスを2つ表現したり範囲検索を失ったりするなど、より複雑になります。 45バイトの長さにするか、varchar / varbinaryを使用しなければならない場合もあります。

  • これの変化は最初に受け取られたようにアドレスを保存するのをサポートできます。 それはめったに望まれないかもしれませんが、それがあなたが多くの利益を失うとき。

  • フルフォーマットで区切り文字を削除して、保存するだけで、手間が省け、効率が上がります。 接頭辞の索引付けが重要な場合(BINARY(128))、これは長い道のりです。

  • BIGINT UNSIGNED * 2 *

長所:

  • 2列であることに関して余分なことをしなければならないという警告とともに、数学演算子および関数を処理します。

  • 効率的ですが、これも2列であることに注意が必要です。

  • 基本索引(完全、範囲)で機能します。

  • prefixが64ビットのとき、prefix indexで動作します。

  • わかりやすいフォーマットを表示します。

短所:

  • 2つの列はそれを非アトミックにし、それに対する多くの操作の倍増を意味します。

奇数:

  • 現代の多くの言語やシステムは64ビットの整数を与えますが、符号なしを与えません。 署名が問題です。 負の数は正の数よりも少ないものとして存在しますが、それらのビットシーケンスは実際にはより高いです。 このため、代わりに4 * INT UNSIGNEDを使用するのが一般的です。

  • 同様に、人々はそれをプレフィックスインデックスのために分割するかもしれません、そしてあなたは少なくとも8ビットまで行くことができます(TINYINT UNSIGNED)。 MySQLがビット型のインデックスを正しく複合していると仮定して、フルプレフィックスインデックスにBIT(1)型を使用する人もいます。

  • 繰り返しますが、4列の場合も同様に、計算中のスラックビットにより、皮肉にも計算が簡単になります(計算の中間値は64ビットになることがあります)。

概要

人々はさまざまな理由でさまざまなフォーマットを使用します。 下位互換性が1つの理由である可能性があり、それはIPv4に対して行われていたことに依存します。 他の人たちは、アドレスがどのように使われているか、そしてそれに関する最適化にかかっています。 あなたは複数のアプローチが使われているのを見るかもしれません。

B16は最も効率的で手間のかからないので、B16が良いデフォルトのアプローチです。

PHPでの変換では、次のように調べれば手作業で変換できます。

  • gmpまたはbcmath

  • PHPの数値処理とビット演算子、特にintやfloatの制限と、それに依存する関数はそうでなければ役に立つと思われることに特に注意してください。

  • IPv6フォーマット

  • pack / unpack、bin2hex / hex2bin。

しかし私はIPv6のさまざまな表示フォーマットを扱うために共通のライブラリを使うことをお勧めします。