給定兩個文件的絕對或相對路徑,計算從文件 A 到文件 B 的相對路徑(如 ../../z/x/y.php),常用於模板引擎、資源引用、構建工具。
/ 分割為數組。$i。$a_len - $i 級(每級 ../)。$i 開始拼接剩餘目錄及文件名。<?php
/**
* 計算從 $pathA 到 $pathB 的相對路徑
* @param string $pathA 起始文件路徑
* @param string $pathB 目標文件路徑
* @return string 相對路徑
*/
function getRelativePath($pathA, $pathB) {
// 統一分隔符,去除首尾斜杠
$pathA = trim(str_replace('\\', '/', $pathA), '/');
$pathB = trim(str_replace('\\', '/', $pathB), '/');
$arrA = explode('/', $pathA);
$arrB = explode('/', $pathB);
// 彈出文件名
$fileA = array_pop($arrA);
$fileB = array_pop($arrB);
$lenA = count($arrA);
$lenB = count($arrB);
// 找到公共前綴長度
$i = 0;
while ($i < $lenA && $i < $lenB && $arrA[$i] === $arrB[$i]) {
$i++;
}
$rel = '';
// 向上返回
for ($j = 0; $j < $lenA - $i; $j++) {
$rel .= '../';
}
// 向下進入
for (; $i < $lenB; $i++) {
$rel .= $arrB[$i] . '/';
}
$rel .= $fileB;
return $rel;
}
// 測試
$pathA = 'a/b/c/d/e/f.php';
$pathB = 'a/b/z/x/y.php';
echo getRelativePath($pathA, $pathB); // 輸出: ../../../z/x/y.php
// 邊界測試
echo getRelativePath('a/b/c.php', 'a/b/d.php'); // d.php
echo getRelativePath('a/b/c.php', 'x/y/z.php'); // ../../x/y/z.php
echo getRelativePath('/var/www/a.php', '/var/www/b.php'); // b.php
?>
function getRelativePathModern($from, $to) {
$from = (new SplFileInfo($from))->getRealPath();
$to = (new SplFileInfo($to))->getRealPath();
if ($from === false || $to === false) return false;
$fromParts = explode(DIRECTORY_SEPARATOR, $from);
$toParts = explode(DIRECTORY_SEPARATOR, $to);
array_pop($fromParts); // 移除文件名
array_pop($toParts);
$i = 0;
while (isset($fromParts[$i]) && isset($toParts[$i]) && $fromParts[$i] === $toParts[$i]) {
$i++;
}
$up = count($fromParts) - $i;
$rel = str_repeat('..' . DIRECTORY_SEPARATOR, $up);
$rel .= implode(DIRECTORY_SEPARATOR, array_slice($toParts, $i));
$rel .= DIRECTORY_SEPARATOR . basename($to);
return $rel;
}
realpath() 解析符號鏈接、統一分隔符。