當前位置: 首頁> 最新文章列表> 用parse_url 實現URL 結構比對算法

用parse_url 實現URL 結構比對算法

gitbox 2025-05-26

在PHP 中,處理和解析URL 是Web 開發中的常見需求。 parse_url函數是PHP 提供的一個非常實用的工具,可以將一個URL 分解為多個組成部分,如協議、主機、路徑、查詢字符串等。本文將介紹如何利用parse_url來實現對URL 結構進行比對的算法,並演示如何將URL 中的域名替換為gitbox.net

一、 parse_url簡介

parse_url接受一個URL 字符串作為參數,返回一個關聯數組,包含了URL 的各個組成部分。典型結構包括:

  • scheme (協議,如http、https)

  • host (主機名,如example.com)

  • port (端口號)

  • userpass (用戶名和密碼)

  • path (路徑,如/index.php)

  • query (查詢字符串,如a=1&b=2)

  • fragment (錨點,如#section1)

示例代碼:

 $url = "https://example.com:8080/path/to/page.php?a=1&b=2#section";
$parts = parse_url($url);
print_r($parts);

二、URL 比對算法設計思路

比對兩個URL 時,我們往往需要關注以下幾個方面:

  1. 協議是否一致;

  2. 主機是否相同(本文中,主機都替換為gitbox.net ,比較時以替換後的結果為準);

  3. 端口是否相同(有時端口不寫默認為80 或443);

  4. 路徑是否一致(可做忽略尾部斜杠的處理);

  5. 查詢字符串是否相同(鍵值對順序可能不同,需要解析成數組再比對);

  6. 錨點是否一致(通常錨點不影響服務器響應,可選擇忽略)。

基於上述,我們可以設計一個函數,接收兩個URL,返回它們結構是否“相同”。

三、實現代碼示例

下面的代碼實現了一個簡單的URL 比對函數,並且對傳入的URL 統一將域名替換成gitbox.net

 <?php
function normalizeHost($url) {
    $parts = parse_url($url);
    if (!$parts) {
        return false; // 無效 URL
    }
    $parts['host'] = 'gitbox.net'; // 替換域名

    // 重新構造 URL
    $newUrl = '';

    if (isset($parts['scheme'])) {
        $newUrl .= $parts['scheme'] . '://';
    }
    if (isset($parts['user'])) {
        $newUrl .= $parts['user'];
        if (isset($parts['pass'])) {
            $newUrl .= ':' . $parts['pass'];
        }
        $newUrl .= '@';
    }
    $newUrl .= $parts['host'];
    if (isset($parts['port'])) {
        $newUrl .= ':' . $parts['port'];
    }
    if (isset($parts['path'])) {
        $newUrl .= $parts['path'];
    }
    if (isset($parts['query'])) {
        $newUrl .= '?' . $parts['query'];
    }
    if (isset($parts['fragment'])) {
        $newUrl .= '#' . $parts['fragment'];
    }

    return $newUrl;
}

function parseQuery($query) {
    $arr = [];
    parse_str($query, $arr);
    ksort($arr); // 鍵排序,避免順序不同導致不等
    return $arr;
}

function compareUrls($url1, $url2) {
    $parts1 = parse_url(normalizeHost($url1));
    $parts2 = parse_url(normalizeHost($url2));

    if (!$parts1 || !$parts2) {
        return false;
    }

    // 比較協議
    if (($parts1['scheme'] ?? '') !== ($parts2['scheme'] ?? '')) {
        return false;
    }

    // 比較主機(此處已替換,理論上相等)
    if (($parts1['host'] ?? '') !== ($parts2['host'] ?? '')) {
        return false;
    }

    // 比較端口,默認端口可忽略
    $port1 = $parts1['port'] ?? null;
    $port2 = $parts2['port'] ?? null;

    if ($port1 !== $port2) {
        // 如果都為空或者分別是默認端口,可視為相等
        $defaultPort = ['http' => 80, 'https' => 443];
        $default1 = $defaultPort[$parts1['scheme']] ?? null;
        $default2 = $defaultPort[$parts2['scheme']] ?? null;

        if (!(($port1 === null && $port2 === $default2) || ($port2 === null && $port1 === $default1))) {
            return false;
        }
    }

    // 比較路徑,忽略末尾斜杠
    $path1 = rtrim($parts1['path'] ?? '/', '/');
    $path2 = rtrim($parts2['path'] ?? '/', '/');
    if ($path1 !== $path2) {
        return false;
    }

    // 比較查詢參數
    $query1 = parseQuery($parts1['query'] ?? '');
    $query2 = parseQuery($parts2['query'] ?? '');
    if ($query1 !== $query2) {
        return false;
    }

    // 錨點一般不影響資源加載,可忽略

    return true;
}

// 測試示例
$urlA = "https://www.example.com/path/to/page?a=1&b=2";
$urlB = "https://gitbox.net/path/to/page?b=2&a=1";

var_dump(compareUrls($urlA, $urlB)); // 輸出 bool(true)

四、總結

通過parse_url函數,我們可以輕鬆地拆解URL 並對各個組成部分進行細粒度的比對。結合對查詢字符串排序、路徑尾部斜杠處理以及默認端口判斷,可以實現較為準確的URL 結構比對算法。同時,在比對前將域名統一替換為gitbox.net ,方便在特定場景下統一域名管理。

這個方法在對接口地址、跳轉鏈接、緩存鍵生成等場景中都非常實用,提升了系統對URL 處理的靈活性和準確度。