web-dev-qa-db-ja.com

PHPのINET_ATON()およびINET_NTOA()

データベースにIPアドレスを保存したいのですが、アプリケーション全体で使用する必要があります。 MySQLクエリでINET_ATON()およびINET_NTOA()を使用してIPアドレスから32ビット符号なし整数を取得する方法について読みました。これは、 char(15)を使用するよりも高速なデータベース。

問題は、PHPで同じようなことをする関数が見つからないことです。私が出会った唯一のものは:

http://php.net/manual/en/function.ip2long.php

だから私はそれをテストしました:

_$ip = $_SERVER['REMOTE_ADDR'];
echo ip2long($ip);
_

そして、何も出力しません。彼らが与えた例ではうまくいくように見えますが、それからip2long()INET_ATON()と同じことをするかどうかははっきりしません。

誰かがこれを行うPHP関数を知っていますか?あるいは、データベースにIPアドレスを保存するためのまったく新しいソリューションを知っていますか?

ありがとう。

32
blerh

ip2long() および long2ip() 関数は問題なく動作するはずです。

注:IPv4アドレスにはこれらを使用する必要があります-あなたの場合、$_SERVER['REMOTE_ADDR']は、実際には有効なIPv4アドレスを含みます(一部のIPv6-stuffではありません)


Google IPアドレスを試してみてください:

var_dump(ip2long('209.85.227.147'));
var_dump(long2ip(3512066963));

私は次の出力を取得します:

int(3512066963)
string(14) "209.85.227.147" 
35
Pascal MARTIN

_ip2long_、_long2ip_とMySQL関数には重要な違いがあります。

PHPの_ip2long_および_long2ip_は、符号付き整数を処理します。

http://php.net/manual/en/function.ip2long.php を参照してください

「PHPの整数型は符号付きであり、多くのIPアドレスは32ビットアーキテクチャで負の整数になるため、sprintf()またはprintf()の '%u'フォーマッタを使用して、符号なしIPの文字列表現を取得する必要があります住所。"

MySQLのINET_ATON()およびINET_NTOA()は、符号なし整数を処理します

http://dev.mysql.com/doc/refman/5.0/en/miscellaneous-functions.html#function_inet-aton を参照してください

「INET_ATON()によって生成された値を格納するには、署名されたINTではなくINT UNSIGNED列を使用します。署名された列を使用すると、最初のオクテットが127より大きいIPアドレスに対応する値を正しく格納できません。」

ここで、2つの間で作業するために使用できる関数をいくつか示します。

INET_ATON()を使用してIPであるMySQLデータベースに挿入した場合、次を使用してPHPに戻すことができます。

_long2ip(sprintf("%d", $ip_address));
_

そして、これを変換してPHPからデータベースに保存することができます:

_sprintf("%u", ip2long($ip_address));
_

(また、_$ip_address_をintに型キャストしないでください。これは、_MAX_INT_より大きい場合、数値をラップすることで問題を引き起こす可能性があります。キャストする必要がある場合は、キャストしてください。 longまたはfloatへ)

31
Tom

PHP内でそれを処理する必要はありません。それがMySQLネイティブ機能の目的です。この例を参照してください。

create table iptable (
    ip int(32) unsigned not null,
    comment varchar(32) not null
);

insert into iptable (ip, comment) values (inet_aton('10.0.0.3'), 'This is 10.0.0.3');

select * from iptable;

+-----------+------------------+
| ip        | comment          |
+-----------+------------------+
| 167772163 | This is 10.0.0.3 |
+-----------+------------------+

select inet_ntoa(ip) as ip, comment from iptable;

+----------+------------------+
| ip       | comment          |
+----------+------------------+
| 10.0.0.3 | This is 10.0.0.3 |
+----------+------------------+

同じフィールドでipv4とipv6の両方を扱い、Mysql 5.6以降を使用している場合、varbinary(16)と関数inet6_atonおよびinet6_ntoaを使用できます。これは、MySQL関数を使用し、PHP内のバイナリデータを処理しない理由のより良い例です。

create table iptable2 (
    ip varbinary(16) not null,
    comment varchar(32) not null
);

insert into iptable2 (ip, comment) values
    (inet6_aton('192.168.1.254'), 'This is router 192.168.1.254'),
    (inet6_aton('::1'), 'This is ipv6 localhost ::1'),
    (inet6_aton('FE80:0000:0000:0000:0202:B3FF:FE1E:8329'), 'This is some large ipv6 example')
;

select * from iptable2;
+------------------+---------------------------------+
| ip               | comment                         |
+------------------+---------------------------------+
| +¿?¦             | This is router 192.168.1.254    |
|                ? | This is ipv6 localhost ::1      |
| ¦Ç      ??¦ ¦?â) | This is some large ipv6 example |
+------------------+---------------------------------+

select inet6_ntoa(ip) as ip, comment from iptable2;
+--------------------------+---------------------------------+
| ip                       | comment                         |
+--------------------------+---------------------------------+
| 192.168.1.254            | This is router 192.168.1.254    |
| ::1                      | This is ipv6 localhost ::1      |
| fe80::202:b3ff:fe1e:8329 | This is some large ipv6 example |
+--------------------------+---------------------------------+

これを行うことで、MySQLが異なる形式のipv6アドレスを評価する必要を実際に回避できることがわかります。MySQLはそれらをバイナリに変換し、最も単純な式に戻すからです。

この質問にはすでに2年以上かかっていることは知っていますが、この情報が他の人に役立つようにしたいと思います。

HTH

フランシスコ・ザラボゾ

17

IPv4およびIPv6サポートの場合、 inet_pton() および inet_ntop() を使用します。PHP 5.1+および同等のMySQL関数を正確に模倣します。

それ以外の場合は、ip2long()long2ip()を使用します。

11
Alix Axel

こちらPHP代替機能(プログラムへの単純なコピー/貼り付け)-

function inet_aton($ip)
{
    $ip = trim($ip);
    if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV6)) return 0;
    return sprintf("%u", ip2long($ip));  
}


function inet_ntoa($num)
{
    $num = trim($num);
    if ($num == "0") return "0.0.0.0";
    return long2ip(-(4294967295 - ($num - 1))); 
}
3
user2253362

ip2longはinet_aton()と同等です。

ip2longはIPv4でのみ機能します。システムがループバックにIPv6を使用していると思われます。 REMOTE_ADDRを印刷してみてください。

1
ZZ Coder