萬盛學電腦網

您现在的位置: 萬盛學電腦網 >> 程式設計 >  >> 網路程式設計 >> PHP 程式設計

PHP 相對路徑轉絕對 URL 完整方案:preg_replace_callback 處理 href/src/base 標籤

核心函數

/**
 * 將 HTML 內容中的相對路徑轉為絕對 URL
 * @param string $html  原始 HTML
 * @param string $baseUrl 基準 URL (含 scheme+host+path, 如 https://example.com/dir/)
 * @return string 轉換後 HTML
 */
function relativeToAbsolute(string $html, string $baseUrl): string {
    // 確保 baseUrl 以 / 結尾
    $baseUrl = rtrim($baseUrl, '/') . '/';
    
    // 解析 baseUrl 取得 scheme://host
    $parsed = parse_url($baseUrl);
    $origin = $parsed['scheme'] . '://' . $parsed['host'] . (isset($parsed['port']) ? ':' . $parsed['port'] : '');
    
    // 正則匹配 href、src、action、data-src 等屬性
    $pattern = '/\b(href|src|action|data-src|poster|background)\s*=\s*["\']([^"\'>\s]+)["\']/i';
    
    return preg_replace_callback($pattern, function($m) use ($baseUrl, $origin) {
        $attr  = $m[1];
        $value = $m[2];
        
        // 已是絕對 URL 或 data:、javascript:、mailto: 等協議,跳過
        if (preg_match('/^(?:[a-z]+:)?\/\//i', $value) || 
            preg_match('/^(?:data|javascript|mailto|tel):/i', $value)) {
            return $m[0];
        }
        
        // 根相對路徑 /path → origin + path
        if ($value[0] === '/') {
            $absolute = $origin . $value;
        }
        // 相對路徑 path/to → baseUrl + path
        else {
            $absolute = $baseUrl . ltrim($value, './');
        }
        
        return "$attr=\"$absolute\"";
    }, $html);
}

使用範例

$html = '<img src="images/logo.png"> <a href="/about.html">關於</a> <link href="../style.css">';
$base = 'https://example.com/blog/2024/';

echo relativeToAbsolute($html, $base);
// 輸出:
// <img src="https://example.com/blog/2024/images/logo.png"> 
// <a href="https://example.com/about.html">關於</a> 
// <link href="https://example.com/blog/2024/../style.css"> (可再做路徑規範化)

進階:路徑規範化 (移除 ../ .)

function normalizePath(string $path): string {
    $parts = [];
    foreach (explode('/', $path) as $part) {
        if ($part === '' || $part === '.') continue;
        if ($part === '..') array_pop($parts);
        else $parts[] = $part;
    }
    return implode('/', $parts);
}

// 在 callback 中使用
$absolute = $origin . '/' . normalizePath(ltrim($value, '/')); // 根相對
$absolute = $baseUrl . normalizePath(ltrim($value, './'));     // 相對

替代方案:DOMDocument 解析 (更健壯)

function relativeToAbsoluteDom(string $html, string $baseUrl): string {
    $dom = new DOMDocument();
    libxml_use_internal_errors(true);
    $dom->loadHTML('' . $html, LIBXML_HTML_NOIMPLIED | LIBXML_HTML_NODEFDTD);
    libxml_clear_errors();
    
    $xpath = new DOMXPath($dom);
    $attrs = ['href', 'src', 'action', 'data-src', 'poster'];
    
    foreach ($attrs as $attr) {
        foreach ($xpath->query("//@$attr") as $node) {
            $value = $node->value;
            if (preg_match('/^(?:[a-z]+:)?\/\//i', $value)) continue;
            $node->value = $value[0] === '/' 
                ? (parse_url($baseUrl, PHP_URL_SCHEME) . '://' . parse_url($baseUrl, PHP_URL_HOST) . $value)
                : rtrim($baseUrl, '/') . '/' . ltrim($value, './');
        }
    }
    return $dom->saveHTML();
}

應用場景

  • RSS/Atom 內容聚合:來源站相對路徑 → 絕對 URL。
  • 郵件模板渲染:確保圖片、連結在郵件客戶端正常顯示。
  • 爬蟲資料清洗:統一存儲絕對 URL 便於去重、分析。
  • 靜態站點生成:本地預覽時自動注入 <base href> 或轉換連結。
copyright © 萬盛學電腦網 all rights reserved