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

PHP URL 驗證正則表達式:從簡單匹配到 RFC 3986 合規的最佳實踐

     編輯:PHP 綜合知識

原文正則分析

$pattern = "/http:[\/]{2}[a-z]+[.]{1}[a-z\d\-]+[.]{1}[a-z\d]*[\/]*[A-Za-z\d]*[\/]*[A-Za-z\d]*[.]*html/";

問題:

  • 僅匹配 https://,不支援 https。
  • 強制雙層域名 (a.b),無法匹配 localhost、example.com、a.b.c.d。
  • 路徑部分極其死板,只匹配以 .html 結尾。
  • 字符類寫法冗余:[\/]{2} → //,[.]{1} → \.。
  • 未處理端口、查詢參數、片段、用戶信息、IP 地址、國際化域名等合法 URL 組件。

進階方案:PHP 內置驗證 (推薦首選)

<?php
$url = 'https://user:pass@example.com:8080/path?query=value#fragment';

// 1. filter_var (PHP 5.2+) - 最簡單、覆蓋 RFC 基礎規則
if (filter_var($url, FILTER_VALIDATE_URL)) {
    echo "合法 URL";
}

// 2. 額外要求:必須有 scheme + host
if (filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED)) {
    echo "完整 URL";
}

// 3. 解析組件
$parts = parse_url($url);
print_r($parts);
/* Array
(
    [scheme] => https
    [user] => user
    [pass] => pass
    [host] => example.com
    [port] => 8080
    [path] => /path
    [query] => query=value
    [fragment] => fragment
) */

正則表達式方案 (需自定義規則時)

方案一:輕量級實用正則 (覆蓋 95% Web URL)

$regex = '~
    ^                                    # 開始
    (?:https?|ftp)://                    # 協議
    (?:                                  # 用戶信息 (可選)
        [^\s:@/]+(?::[^\s:@/]*)?@
    )?
    (?:                                  # 主機
        (?:[a-z0-9-]+\.)+[a-z]{2,}       # 域名
      |                                  # 或
        \d{1,3}(?:\.\d{1,3}){3}          # IPv4
      |                                  # 或
        \[[a-f0-9:]+\]                   # IPv6
      |                                  # 或
        localhost                        # 本地
    )
    (?::\d{1,5})?                        # 端口 (可選)
    (?:/[^\s?#]*)?                       # 路徑 (可選)
    (?:\?[^\s#]*)?                       # 查詢 (可選)
    (?:\#[^\s]*)?                        # 片段 (可選)
    $                                    # 結束
~ix';

方案二:RFC 3986 近似合規 (複雜、長、維護難,非必要勿用)

參考 Mathias Bynens 收集 或 league/uri 庫內部正則。

方案三:國際化域名 (IDN) 支援

// 需 intl 擴展
$idn = idn_to_ascii('中文域名.中国'); // -> xn--fiqs8s.xn--fiqs8s
// 驗證時先轉 ASCII 再用正則/filter_var

最佳實踐總結

  1. 首選 filter_var($url, FILTER_VALIDATE_URL):標準庫、無依賴、持續更新、覆蓋絕大多數合法 URL。
  2. 需嚴格限制 (如僅允許 http/https、必須有 TLD):在 filter_var 基礎上輔以 parse_url() 解析後進一步判斷 $parts['scheme'], $parts['host'] 等。
  3. 避免手寫複雜正則:URL 語法極其複雜 (RFC 3986/3987),手寫正則極易遺漏邊界情況 (IPv6、百分號編碼、子分隔符、Unicode 等)。
  4. 安全場景 (防 SSRF、XSS):驗證後**再次**用 parse_url 取 host,做 DNS 解析、IP 白名單/黑名單、內網 IP 檢測 (filter_var($ip, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE))。

代碼片段:生產級 URL 驗證器

function isValidUrl(string $url, array $allowedSchemes = ['http', 'https']): bool {
    if (!filter_var($url, FILTER_VALIDATE_URL, FILTER_FLAG_SCHEME_REQUIRED | FILTER_FLAG_HOST_REQUIRED)) {
        return false;
    }
    $parts = parse_url($url);
    if (!in_array(strtolower($parts['scheme']), $allowedSchemes, true)) {
        return false;
    }
    // 可選:禁止內網 IP (防 SSRF)
    if (isset($parts['host'])) {
        $ip = gethostbyname($parts['host']); // 簡單解析,生產用 dns_get_record
        if (filter_var($ip, FILTER_VALIDATE_IP, FILTER_FLAG_NO_PRIV_RANGE | FILTER_FLAG_NO_RES_RANGE) === false) {
            return false; // 內網/保留 IP
        }
    }
    return true;
}
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved