首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
您现在的位置: 程式碼之家 >> 編程語言 >  >> 網頁程式設計 >> PHP 程式設計 >> PHP 相關知識

PHP 取得檔案相對路徑工具函式:任意兩路徑相對關係計算

     編輯:PHP 相關知識

PHP 取得檔案相對路徑工具函式:任意兩路徑相對關係計算

在建構資源路徑、產生相對連結、遷移檔案系統時,常需計算「路徑 B 相對於路徑 A 的相對路徑」。PHP 內建 realpath() 只能取得絕對路徑,無相對路徑計算函式。本文提供通用工具函式實作與邏輯解析。

核心演算法邏輯

  1. 將兩路徑以 / 分割為陣列。
  2. 找出共同前綴 (Common Prefix)。
  3. 路徑 A 剩餘段數 → 對應數量的 .. (上層目錄)。
  4. 路徑 B 剩餘段 → 直接保留。
  5. 合併 .. 序列與路徑 B 剩餘段。

通用工具函式實作

<?php
/**
 * 計算 $targetPath 相對於 $basePath 的相對路徑
 * 
 * @param string $basePath 基準路徑 (通常為目錄,以 / 結尾)
 * @param string $targetPath 目標路徑 (檔案或目錄)
 * @return string 相對路徑 (如: ../../folder/file.php)
 */
function getRelativePath(string $basePath, string $targetPath): string {
    // 1. 正規化:移除尾部斜線、統一分隔符
    $basePath = rtrim(str_replace('\\', '/', $basePath), '/');
    $targetPath = rtrim(str_replace('\\', '/', $targetPath), '/');
    
    // 2. 若為檔案路徑,basePath 取目錄部分
    if (!is_dir($basePath) && strpos($basePath, '.') !== false) {
        $basePath = dirname($basePath);
    }
    
    // 3. 分割路徑段
    $baseParts = explode('/', $basePath);
    $targetParts = explode('/', $targetPath);
    
    // 4. 找出共同前綴長度
    $commonLength = 0;
    $minLength = min(count($baseParts), count($targetParts));
    for ($i = 0; $i < $minLength; $i++) {
        if ($baseParts[$i] === $targetParts[$i]) {
            $commonLength++;
        } else {
            break;
        }
    }
    
    // 5. 構建相對路徑
    $upLevels = count($baseParts) - $commonLength;
    $relativeParts = array_merge(
        array_fill(0, $upLevels, '..'),           // 上層目錄序列
        array_slice($targetParts, $commonLength)  // 目標剩餘段
    );
    
    // 6. 特殊情況:同一目錄
    if (empty($relativeParts)) {
        return '.';
    }
    
    return implode('/', $relativeParts);
}

// 測試範例
$a = '/a/b/c/d/e.php';
$b = '/a/b/12/34/c.php';
echo getRelativePath($a, $b); // 輸出: ../../12/34/c.php

// 更多測試
var_dump(getRelativePath('/var/www/html', '/var/www/html/index.php')); // index.php
var_dump(getRelativePath('/var/www/html/index.php', '/var/www/html')); // ..
var_dump(getRelativePath('/a/b/c', '/x/y/z')); // ../../../x/y/z
var_dump(getRelativePath('/a/b/c/', '/a/b/c/d/e.php')); // d/e.php
?>

進階版:支援 URL 與 Windows 路徑

<?php
function getRelativePathAdvanced($base, $target, $isUrl = false) {
    $sep = $isUrl ? '/' : DIRECTORY_SEPARATOR;
    $base = rtrim(str_replace(['\\', '/'], $sep, $base), $sep);
    $target = rtrim(str_replace(['\\', '/'], $sep, $target), $sep);
    
    // URL 不檢查 is_dir,直接按字串處理
    if (!$isUrl && !is_dir($base) && pathinfo($base, PATHINFO_EXTENSION)) {
        $base = dirname($base);
    }
    
    $baseParts = explode($sep, $base);
    $targetParts = explode($sep, $target);
    
    $common = 0;
    foreach ($baseParts as $i => $part) {
        if (isset($targetParts[$i]) && $targetParts[$i] === $part) {
            $common++;
        } else break;
    }
    
    $up = count($baseParts) - $common;
    $rel = array_merge(array_fill(0, $up, '..'), array_slice($targetParts, $common));
    
    return $rel ? implode($sep, $rel) : '.';
}
?>

內建函式替代方案 (PHP 5.3+)

若基準路徑為目錄,可利用 realpath() + 字串處理:

<?php
function getRelativePathRealpath($baseDir, $targetPath) {
    $baseDir = rtrim(realpath($baseDir), DIRECTORY_SEPARATOR) . DIRECTORY_SEPARATOR;
    $targetPath = realpath($targetPath);
    
    if (strpos($targetPath, $baseDir) === 0) {
        return substr($targetPath, strlen($baseDir));
    }
    
    // 不在同一樹下,退回通用演算法
    return getRelativePath($baseDir, $targetPath);
}
?>

應用場景範例

  • HTML 基準路徑:<base href="..."> 計算資源相對路徑。
  • CSS/JS 打包:Source Map 來源檔案相對路徑。
  • 檔案遷移腳本:保持目錄結構複製/移動。
  • 模板引擎:include、extends 路徑解析。
  • API 路由:根據請求路徑計算控制器相對位置。
  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved