核心函數
/**
* 將 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> 或轉換連結。