首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP IP 地址與整數互轉完整指南:原理、陷阱與最佳實踐

     編輯:PHP 相關知識

內建函數 ip2long / long2ip 基礎用法

<?php
$ip = '210.110.11.49';
$int = ip2long($ip);        // -764540111 (有號整數)
$unsigned = sprintf('%u', $int); // 3530427185 (無號整數)
echo long2ip($int);         // 210.110.11.49
?>

關鍵點:PHP 整數為有號 32 位元,IP 轉換結果可能為負數。資料庫儲存建議使用 UNSIGNED INT 欄位,PHP 端用 sprintf('%u', $int) 或 $int & 0xFFFFFFFF 轉無號值。

前導零陷阱:ip2long 的隱藏 Bug

<?php
// 錯誤示範
$ip = '210.110.011.49';  // 第三段有前導零
echo ip2long($ip);       // -764540623
echo long2ip($ip);       // 210.110.9.49  ← 錯誤!解析為八進位

$ip = '021.110.11.49';   // 第一段有前導零
echo ip2long($ip);       // 292424497
echo long2ip($ip);       // 17.110.11.49  ← 錯誤!
?>

原因:PHP 將帶前導零的數字字串視為八進位。011 → 九進位 9,021 → 八進位 17。

解決方案:預處理移除前導零

<?php
function cleanIp($ip) {
    return implode('.', array_map('intval', explode('.', $ip)));
}

$ip = cleanIp('210.110.011.49'); // 210.110.11.49
echo ip2long($ip); // 正確
?>

手動實現演算法(避開前導零問題)

方法一:位元位移運算(效能最佳)

<?php
function ipToInt($ip) {
    $seg = explode('.', $ip);
    return (intval($seg[0]) << 24)
         | (intval($seg[1]) << 16)
         | (intval($seg[2]) << 8)
         |  intval($seg[3]);
}

function intToIp($int) {
    return ($int >> 24 & 255) . '.'
         . ($int >> 16 & 255) . '.'
         . ($int >> 8 & 255) . '.'
         . ($int & 255);
}
?>

方法二:乘冪累加(直觀易懂)

<?php
function ipToInt($ip) {
    $seg = explode('.', $ip);
    $num = 0;
    foreach ($seg as $i => $v) {
        $num += intval($v) * pow(256, 3 - $i);
    }
    return $num;
}
?>

IP 合法性驗證

<?php
// 方法一:手動檢查各段範圍
function checkIp($ip) {
    $seg = explode('.', $ip);
    if (count($seg) !== 4) return false;
    foreach ($seg as $v) {
        if (!ctype_digit($v) || $v > 255) return false;
    }
    return true;
}

// 方法二:利用 ip2long 特性 (需先 cleanIp)
function checkIp2($ip) {
    $ip = cleanIp($ip);
    return ip2long($ip) !== false;
}
?>

儲存建議總結

  • MySQL 欄位:INT UNSIGNED NOT NULL
  • 寫入前:$int = sprintf('%u', ip2long(cleanIp($ip)))
  • 讀出時:long2ip($int) 直接還原
  • 查詢範圍:WHERE ip_int BETWEEN start AND end 極高效能
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved