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

PHP 獲取當前腳本相對域名根目錄的 Base URL 通用方法

     編輯:PHP 相關知識

PHP 獲取 Base URL(相對域名根目錄)最佳實踐:兼容子目錄部署、反向代理、CLI 模式

在生成站內鏈接、資源路徑、AJAX 請求 URL 時,需要一個**不含域名、以斜槓結尾**的基礎路徑(如 `/myapp/`)。本文提供通用、無框架依賴的獲取方案,解決子目錄部署、URL 重寫、HTTPS 判斷、CLI 環境等實際痛點。

一、核心原理:`$_SERVER['SCRIPT_NAME']` + `dirname()`

SCRIPT_NAME 當前執行腳本相對文檔根目錄的路徑(如 `/myapp/index.php`、`/api/v1/user.php`)。取其目錄部分即為 Base Path。

<?php
/**
 * 獲取 Base URL(相對域名根目錄,以 / 結尾)
 * @return string 如 / /myapp/ /api/v1/
 */
function getBaseUrl(): string {
    // 1. 獲取腳本路徑,統一斜槓
    $scriptName = $_SERVER['SCRIPT_NAME'] ?? '';
    $scriptName = str_replace('\\', '/', $scriptName); // Windows 兼容
    
    // 2. 取目錄部分
    $baseUrl = dirname($scriptName);
    
    // 3. 標準化:空 → '/',去除首尾斜槓後再加斜槓
    $baseUrl = '/' . trim($baseUrl, '/') . '/';
    
    // 4. 特殊情況:CLI 模式無 SCRIPT_NAME
    if (php_sapi_name() === 'cli') {
        return '/'; // 或拋出異常,視業務而定
    }
    
    return $baseUrl;
}

// 使用
$baseUrl = getBaseUrl(); // /myapp/
$assetUrl = $baseUrl . 'assets/css/app.css'; // /myapp/assets/css/app.css
$apiUrl = $baseUrl . 'api/user';             // /myapp/api/user
?>

二、進階:支持反向代理(X-Forwarded-Prefix)

Nginx/Apache 反向代理到子路徑時,需傳遞前綴:

# Nginx
location /myapp/ {
    proxy_pass https://backend/;
    proxy_set_header X-Forwarded-Prefix /myapp;
    proxy_set_header X-Forwarded-Proto $scheme;
    proxy_set_header Host $host;
}

PHP 端優先使用代理頭:

<?php
function getBaseUrlAdvanced(): string {
    // 1. 反向代理注入的前綴(最高優先級)
    if (!empty($_SERVER['HTTP_X_FORWARDED_PREFIX'])) {
        $prefix = rtrim($_SERVER['HTTP_X_FORWARDED_PREFIX'], '/');
        return $prefix ? '/' . $prefix . '/' : '/';
    }
    
    // 2. 標準 SCRIPT_NAME
    $scriptName = $_SERVER['SCRIPT_NAME'] ?? '';
    $scriptName = str_replace('\\', '/', $scriptName);
    $baseUrl = dirname($scriptName);
    $baseUrl = '/' . trim($baseUrl, '/') . '/';
    
    // 3. CLI 兼容
    if (php_sapi_name() === 'cli') return '/';
    
    return $baseUrl;
}
?>

三、框架無關的 URL 生成助手類

<?php
class Url {
    private static $baseUrl = null;
    private static $scheme = null;
    private static $host = null;
    
    public static function base(): string {
        return self::$baseUrl ??= self::detectBaseUrl();
    }
    
    public static function to(string $path): string {
        $path = ltrim($path, '/');
        return self::base() . $path;
    }
    
    public static function asset(string $path): string {
        return self::to('assets/' . ltrim($path, '/'));
    }
    
    public static function full(string $path): string {
        return self::scheme() . '://' . self::host() . self::to($path);
    }
    
    private static function detectBaseUrl(): string {
        if (!empty($_SERVER['HTTP_X_FORWARDED_PREFIX'])) {
            return '/' . trim($_SERVER['HTTP_X_FORWARDED_PREFIX'], '/') . '/';
        }
        $scriptName = str_replace('\\', '/', $_SERVER['SCRIPT_NAME'] ?? '');
        return '/' . trim(dirname($scriptName), '/') . '/';
    }
    
    private static function scheme(): string {
        return self::$scheme ??= (
            (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ||
            (!empty($_SERVER['HTTP_X_FORWARDED_PROTO']) && $_SERVER['HTTP_X_FORWARDED_PROTO'] === 'https')
        ) ? 'https' : 'http';
    }
    
    private static function host(): string {
        return self::$host ??= $_SERVER['HTTP_HOST'] ?? 'localhost';
    }
}

// 使用
echo Url::base();        // /myapp/
echo Url::to('api/user'); // /myapp/api/user
echo Url::asset('css/app.css'); // /myapp/assets/css/app.css
echo Url::full('login');  // https://example.com/myapp/login
?>

四、Zend Framework / Laravel / Symfony 對比

框架獲取 Base URL 方法特點
原生 PHP (本文)自定義函數/類零依賴、可控、適合微型項目
Laravel`url('/')` / `asset()` / `route()`基於 `APP_URL` 配置、自動處理代理、強大
Symfony`$request->getBasePath()` / `asset()`Request 對象封裝、支持子請求、專業
Yii 2`Yii::$app->request->baseUrl` / `Url::to()`組件化、自動檢測、Gii 生成代碼直接用
ThinkPHP`Request::instance()->baseUrl()` / `url()`單例模式、簡潔
Zend/Laminas`$this->url()` (View Helper) / `ServerUrlHelper`視圖助手、靈活但樣板代碼多

五、常見坑與解決

  1. 雙斜槓 `//`:`trim($baseUrl, '/')` 確保首尾無斜槓再拼接。
  2. 反向代理子路徑 404:必須設置 `X-Forwarded-Prefix` 並信任該頭。
  3. HTTPS 判斷失敗:檢查 `HTTP_X_FORWARDED_PROTO` 或 `HTTPS` 變量,配置代理 `proxy_set_header X-Forwarded-Proto $scheme;`。
  4. CLI 腳本報錯:`SCRIPT_NAME` 不存在,返回 `/` 或拋出異常提示需配置 `APP_BASE_URL` 環境變量。
  5. 部署在子目錄但訪問主域名根路徑:Web 服務器配置 `root /var/www/myapp/public;`,則 Base URL 為 `/`。

**最佳實踐**:新項目直接用框架內置 URL 生成器;老項目/微型項目引入本文 `Url` 類,統一管理路徑生成,避免硬編碼導致遷移地獄。

  1. 上一篇文章:
  2. 下一篇文章:
Copyright © 程式碼之家 All Rights Reserved