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

PHP FILTER_VALIDATE_IP 過濾器完整指南:IP 驗證、IPv6、私有/保留地址檢測

     編輯:PHP 相關知識

函數簡介

filter_var($ip, FILTER_VALIDATE_IP, $flags) 是 PHP 內建的 IP 地址驗證函數,支援 IPv4/IPv6、標誌位過濾私有/保留地址,比正則表達式更可靠、效能更好。

基本用法

<?php
$ip = "192.168.0.1";

if (filter_var($ip, FILTER_VALIDATE_IP)) {
  echo "IP 格式合法";
} else {
  echo "IP 格式不合法";
}
// 輸出: IP 格式合法

旗標參數詳細表

常數值作用
FILTER_FLAG_IPV41048576僅允許 IPv4 格式
FILTER_FLAG_IPV61048577僅允許 IPv6 格式
FILTER_FLAG_NO_PRIV_RANGE524288拒絕私有地址(RFC 1918)
FILTER_FLAG_NO_RES_RANGE262144拒絕保留地址(RFC 5735/5156)

私有/保留地址範圍對照

類別範圍旗標攔截
IPv4 私有 (RFC 1918)10.0.0.0/8, 172.16.0.0/12, 192.168.0.0/16NO_PRIV_RANGE
IPv4 回環127.0.0.0/8NO_RES_RANGE
IPv4 Link-local169.254.0.0/16NO_RES_RANGE
IPv4 組播224.0.0.0/4NO_RES_RANGE
IPv4 廣播/保留240.0.0.0/4, 255.255.255.255NO_RES_RANGE
IPv6 回環::1/128NO_RES_RANGE
IPv6 Link-localfe80::/10NO_RES_RANGE
IPv6 唯一本地fc00::/7NO_PRIV_RANGE
IPv6 組播ff00::/8NO_RES_RANGE
IPv6 文檔前綴2001:db8::/32NO_RES_RANGE

實戰範例

1. 僅允許公網 IPv4

<?php
function isPublicIPv4($ip) {
  return filter_var($ip, FILTER_VALIDATE_IP, 
    FILTER_FLAG_IPV4 | FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
  ) !== false;
}

var_dump(isPublicIPv4("8.8.8.8"));      // true  (Google DNS)
var_dump(isPublicIPv4("192.168.1.1"));  // false (私有)
var_dump(isPublicIPv4("127.0.0.1"));    // false (回環)
var_dump(isPublicIPv4("2001:4860:4860::8888")); // false (IPv6)

2. 允許公網 IPv4 + IPv6

<?php
function isPublicIP($ip) {
  return filter_var($ip, FILTER_VALIDATE_IP, 
    FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE
  ) !== false;
}

var_dump(isPublicIP("2001:4860:4860::8888")); // true (Google IPv6 DNS)
var_dump(isPublicIP("::1"));                 // false (IPv6 回環)
var_dump(isPublicIP("fe80::1"));             // false (Link-local)

3. 表單驗證整合

<?php
function validateIpInput($input) {
  $ip = trim($input);
  
  // 基礎格式驗證
  if (!filter_var($ip, FILTER_VALIDATE_IP)) {
    return ['valid' => false, 'error' => 'IP 格式錯誤'];
  }
  
  // 業務邏輯:拒絕私有/保留
  if (!filter_var($ip, FILTER_VALIDATE_IP, 
      FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
    return ['valid' => false, 'error' => '不允許私有/保留 IP'];
  }
  
  return ['valid' => true, 'ip' => $ip];
}

// 測試
$tests = ["192.168.1.1", "8.8.8.8", "2001:db8::1", "not-an-ip", "::1"];
foreach ($tests as $t) {
  print_r(validateIpInput($t));
}

4. 獲取客戶端真實 IP(含代理處理)

<?php
function getClientIp() {
  $headers = [
    'HTTP_CF_CONNECTING_IP',     // Cloudflare
    'HTTP_X_FORWARDED_FOR',      // 標準代理
    'HTTP_X_REAL_IP',            // Nginx proxy
    'HTTP_CLIENT_IP',
    'REMOTE_ADDR'                // 直連
  ];
  
  foreach ($headers as $header) {
    if (!empty($_SERVER[$header])) {
      $ips = explode(',', $_SERVER[$header]);
      $ip = trim($ips[0]); // 取第一個(最原始客戶端)
      if (filter_var($ip, FILTER_VALIDATE_IP, 
          FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE)) {
        return $ip;
      }
    }
  }
  return $_SERVER['REMOTE_ADDR'] ?? 'unknown';
}

常見陷阱

陷阱說明解決
IPv6 壓縮寫法::1、2001:db8:: 合法但易被忽略直接用 filter_var,原生支援
IPv4 映射 IPv6::ffff:192.168.1.1 會被視為 IPv6需配合 FILTER_FLAG_IPV4 排除
前導零192.168.001.001 在某些版本被視為八進位PHP 7.1+ 已修正,建議升級
CIDR 記法192.168.1.0/24 會驗證失敗需自行解析 CIDR,filter_var 不支援

效能對比

<?php
$ips = array_fill(0, 100000, '192.168.1.1');

$t = microtime(true);
foreach ($ips as $ip) filter_var($ip, FILTER_VALIDATE_IP);
echo "filter_var: " . (microtime(true)-$t) . "s\n";

$t = microtime(true);
foreach ($ips as $ip) preg_match('/^(\d{1,3}\.){3}\d{1,3}$/', $ip);
echo "preg_match: " . (microtime(true)-$t) . "s\n";

// 典型結果: filter_var 約 0.02s, preg_match 約 0.08s (快 4 倍)

總結

  • 首選 filter_var:內建、快、支援 IPv6、旗標靈活
  • 組合旗標:FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE 是公網 IP 驗證黃金組合
  • 不要自己寫正則:IPv6 複雜度極高,極易漏情況
  • 代理環境:務必解析 X-Forwarded-For 並再次驗證
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved