IPv4 地址轉無符號 32 位整數,便於資料庫範圍查詢、索引優化、位掩碼運算。本文對比 PHP 內建 ip2long、手動位運算、MySQL INET_ATON 三種方案的行為差異與最佳實踐。
$ip = '192.168.1.101';
$long = ip2long($ip);
echo $long; // -1062731675 (有符號 32 位)
// 轉無符號顯示
printf('%u', $long); // 3232235877
// 反向轉換
echo long2ip($long); // 192.168.1.101
printf('%u') 或 sprintf('%u') 獲取無符號值;long2ip() 自動處理有符號輸入;false。function ip2long_manual(string $ip): int {
$parts = explode('.', $ip);
if (count($parts) !== 4) return 0;
// 位移拼接
return (($parts[0] << 24) | ($parts[1] << 16) | ($parts[2] << 8) | $parts[3]) & 0xFFFFFFFF;
}
// 使用
$long = ip2long_manual('192.168.1.101');
echo $long; // 3232235877 (已是無符號值)
& 0xFFFFFFFF 確保 32 位截斷;ip2long 時。-- IP 轉整數
SELECT INET_ATON('192.168.1.101'); -- 3232235877
-- 整數轉 IP
SELECT INET_NTOA(3232235877); -- 192.168.1.101
-- 範圍查詢:查找 192.168.1.0/24 內的記錄
SELECT * FROM logs
WHERE ip_int BETWEEN INET_ATON('192.168.1.0') AND INET_ATON('192.168.1.255');
INET_ATON 返回無符號整數(BIGINT),範圍查詢極快;inet 類型)。| 輸入 | ip2long() | 手動位運算 | INET_ATON |
|---|---|---|---|
| 192.168.1.101 | -1062731675 | 3232235877 | 3232235877 |
| 255.255.255.255 | -1 | 4294967295 | 4294967295 |
| 0.0.0.0 | 0 | 0 | 0 |
| invalid | false | 0 | NULL |
INT UNSIGNED (MySQL) / BIGINT (通用);$ip_int = sprintf('%u', ip2long($ip)) 或 INET_ATON();long2ip($row['ip_int']) 或 INET_NTOA();CREATE INDEX idx_ip ON logs(ip_int),範圍查詢走索引。VARBINARY(16) + INET6_ATON()/INET6_NTOA();inet_pton()/inet_ntop() 轉二進制字串存儲。| 代碼 | 問題 | 修正 |
|---|---|---|
ip2long($_SERVER['REMOTE_ADDR']) | 可能返回 false(IPv6、代理頭) | 驗證返回值、優先用 filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_IPV4) |
WHERE ip = ip2long('1.2.3.4') | 有符號比較錯誤 | 用 sprintf('%u', ...) 或資料庫 INET_ATON |
long2ip(-1) | 返回 255.255.255.255 正確 | 無問題,long2ip 內部處理 |
統一使用 ip2long + sprintf('%u') 或資料庫 INET_ATON,能構建高性能、可遷移的 IP 存儲查詢體系。