建立符號連結、生成相對 URL、檔案搬移等場景需計算「目標路徑相對於基準路徑」的相對路徑。PHP 無內建函數,本文提供一個不限層級、純字串運算的通用函數。
/**
* 取得 $target 相對於 $base 的相對路徑
* @param string $base 基準目錄 (絕對路徑,建議以 / 結尾)
* @param string $target 目標路徑 (檔案或目錄)
* @return string 相對路徑 (如 ../../target/dir)
*/
function getRelativePath(string $base, string $target): string {
// 正規化:移除尾斜線、統一分隔符
$base = rtrim(str_replace('\\', '/', $base), '/');
$target = rtrim(str_replace('\\', '/', $target), '/');
// 取得目錄部分 (若為檔案)
$baseDir = dirname($base);
$targetDir = dirname($target);
// 分割路徑段
$baseParts = explode('/', $baseDir);
$targetParts = explode('/', $targetDir);
// 找出共同前綴長度
$commonLen = 0;
$minLen = min(count($baseParts), count($targetParts));
for ($i = 0; $i < $minLen; $i++) {
if ($baseParts[$i] === $targetParts[$i]) {
$commonLen++;
} else {
break;
}
}
// 向上層級數 = base 深度 - 共同深度
$upLevels = count($baseParts) - $commonLen;
// 組裝相對路徑
$relative = str_repeat('../', $upLevels);
$relative .= implode('/', array_slice($targetParts, $commonLen));
return $relative ?: '.';
}
// 測試
echo getRelativePath('/var/www/html/project/a/b/', '/var/www/html/project/c/d/e.txt');
// 輸出: ../../c/d
echo getRelativePath('/home/user/docs/', '/home/user/docs/sub/file.txt');
// 輸出: sub
.。../../.. 但實際無效,建議先檢查 strtoupper(substr($base,0,2)) !== strtoupper(substr($target,0,2)) 回傳絕對路徑。realpath() 解析實體路徑。function getRelativeUrlPath(string $baseUrl, string $targetUrl): string {
$basePath = parse_url($baseUrl, PHP_URL_PATH);
$targetPath = parse_url($targetUrl, PHP_URL_PATH);
return getRelativePath($basePath, $targetPath);
}
以目錄分段比對共同前綴、計算 ../ 數量、拼接剩餘段落,即可得到通用相對路徑。函數無外部依賴、效能極佳 (O(n) 字串操作),適合任意深度目錄結構。