MySQL |
---|
INT:0 ~ 4294967295
mysql> SELECT INET_ATON("0.0.0.0"); #0 mysql> SELECT INET_ATON("255.255.255.255"); #4294967295 mysql> SELECT INET_NTOA("0"); #0.0.0.0 mysql> SELECT INET_NTOA("4294967295"); #255.255.255.255註: INET_ATON = Address to number INET_NTOA = Number to Address |
PHP(32 bit) |
---|
INT:-2147483648 ~ 2147483647
var_dump(ip2long("0.0.0.0")); #int(0) var_dump(ip2long("127.255.255.255")); #int(2147483647) var_dump(ip2long("255.255.255.255")); #int(-1) var_dump(ip2long("128.0.0.0")); #int(-2147483648) var_dump(long2ip(0)); #string(7) "0.0.0.0" var_dump(long2ip(2147483647)); #string(15) "127.255.255.255" var_dump(long2ip(-1)); #string(15) "255.255.255.255" var_dump(long2ip(-2147483648)); #string(9) "128.0.0.0"因為在32位元系統,PHP int 型態有分正負號(signed), 範圍為 -2147483648 ~ 2147483647(http://php.net/manual/en/function.intval.php) 可用 sprintf(%u) 轉換成不帶正負號的 (unsigned) 的10進制字串, 可轉成:"0" ~ "4294967295" var_dump(sprintf("%u", ip2long("0.0.0.0"))); #string(1) "0" var_dump(sprintf("%u", ip2long("127.255.255.255"))); #string(10) "2147483647" var_dump(sprintf("%u", ip2long("255.255.255.255"))); #string(10) "4294967295" var_dump(sprintf("%u", ip2long("128.0.0.0"))); #string(10) "2147483648" var_dump(long2ip(0)); #string(7) "0.0.0.0" var_dump(long2ip(2147483647)); #string(15) "127.255.255.255" var_dump(long2ip(4294967295)); #string(15) "255.255.255.255" var_dump(long2ip(2147483648)); #string(9) "128.0.0.0" |
PHP(64 bit) |
---|
INT:0 ~ 4294967295
var_dump(ip2long("0.0.0.0")); #int(0) var_dump(ip2long("127.255.255.255")); #int(2147483647) var_dump(ip2long("255.255.255.255")); #int(4294967295) var_dump(ip2long("128.0.0.0")); #int(2147483648) var_dump(long2ip(0)); #string(7) "0.0.0.0" var_dump(long2ip(2147483647)); #string(15) "127.255.255.255" var_dump(long2ip(4294967295)); #string(15) "255.255.255.255" var_dump(long2ip(2147483648)); #string(9) "128.0.0.0" 在 64 位元的 PHP,int 最大值可到 9223372036854775807, 有無用 sprintf(%u) 不影響轉出的數字範圍 var_dump(sprintf("%u", ip2long("0.0.0.0"))); #string(1) "0" var_dump(sprintf("%u", ip2long("127.255.255.255"))); #string(10) "2147483647" var_dump(sprintf("%u", ip2long("255.255.255.255"))); #string(10) "4294967295" var_dump(sprintf("%u", ip2long("128.0.0.0"))); #string(10) "2147483648" var_dump(long2ip(0)); #string(7) "0.0.0.0" var_dump(long2ip(2147483647)); #string(15) "127.255.255.255" var_dump(long2ip(4294967295)); #string(15) "255.255.255.255" var_dump(long2ip(2147483648)); #string(9) "128.0.0.0" [其他測試] 64 位元的 PHP 將 32 位元的負數結果轉回 IP,似乎也可正常執行(環境:PHP 7.0.12) var_dump(long2ip(-1)); #string(15) "255.255.255.255" var_dump(long2ip(-2)); #string(15) "255.255.255.254" var_dump(long2ip(-3)); #string(15) "255.255.255.253" var_dump(long2ip(-2147483647)); #string(9) "128.0.0.1" var_dump(long2ip(-2147483648)); #string(9) "128.0.0.0" |
結論:
- IP 轉數字存進 MySQL,MySQL 欄位建議使用 INT UNSIGNED,只須 4 bytes,儲存範圍剛好 0~4294967295
- 可用 MySQL INET_ATON() 將IP處理成數字存入。
- 或先用 PHP long2ip() 處理成數字(要相容 32bit PHP,則long2ip的值須再用 sprintf(%u) 處理)
參考:
- https://dev.mysql.com/doc/refman/5.7/en/miscellaneous-functions.html#function_inet-aton
「To store values generated by INET_ATON(), use an INT UNSIGNED column rather than INT, which is signed. If you use a signed column, values corresponding to IP addresses for which the first octet is greater than 127 cannot be stored correctly. See Section 11.2.6, “Out-of-Range and Overflow Handling”.」 - http://php.net/manual/en/function.ip2long.php
- http://php.net/manual/en/function.sprintf.php
- sql - INET_ATON() and INET_NTOA() in PHP? - Stack Overflow
- http://php.net/manual/en/function.intval.php
- PHP ip2long() 回傳值為負數 的 解法 - Tsung's Blog
沒有留言:
張貼留言