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

PHP 獲取當前 URL、域名、端口與查詢字串完整指南

     編輯:PHP 綜合知識

核心超全域變數 $_SERVER

所有 URL 相關資訊皆來自 $_SERVER,關鍵鍵值如下:

鍵名說明範例
REQUEST_URI請求 URI(含查詢字串)/path/script.php?a=1&b=2
PHP_SELF當前腳本路徑(相對 DocumentRoot)/path/script.php
QUERY_STRING查詢字串(不含 ?)a=1&b=2
HTTP_HOSTHost 標頭(含端口若非標準)example.com:8080
SERVER_NAME伺服器設定主機名example.com
SERVER_PORT伺服器監聽端口80 / 443
HTTPS是否 HTTPS(on/off)on
REQUEST_SCHEME請求協定(http/https)https
HTTP_REFERER來源頁面 URL(不可靠)https://google.com/

常用 URL 組裝函數

2.1 取得完整當前 URL(含協定、域名、端口、路徑、查詢)

function getCurrentUrl(): string
{
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') || 
              (isset($_SERVER['REQUEST_SCHEME']) && $_SERVER['REQUEST_SCHEME'] === 'https')
              ? 'https' : 'http';

    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? '';
    $uri  = $_SERVER['REQUEST_URI'] ?? '';

    // 非標準端口才顯示
    $port = $_SERVER['SERVER_PORT'] ?? 80;
    if (($scheme === 'http' && $port != 80) || ($scheme === 'https' && $port != 443)) {
        // HTTP_HOST 已含端口,避免重複
        if (strpos($host, ':') === false) {
            $host .= ':' . $port;
        }
    }

    return $scheme . '://' . $host . $uri;
}

2.2 僅取得域名(不含端口、路徑)

function getDomain(): string
{
    $host = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? '';
    return preg_replace('/:\d+$/', '', $host); // 移除端口
}

2.3 取得基礎 URL(協定 + 域名 + 端口,無路徑)

function getBaseUrl(): string
{
    $scheme = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off') ? 'https' : 'http';
    $host   = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? '';
    return $scheme . '://' . $host;
}

2.4 取得當前腳本目錄 URL(適合生成資源路徑)

function getScriptDirUrl(): string
{
    $base = getBaseUrl();
    $scriptDir = dirname($_SERVER['SCRIPT_NAME'] ?? $_SERVER['PHP_SELF'] ?? '/');
    return rtrim($base . $scriptDir, '/') . '/';
}

常見陷阱與注意事項

  1. HTTP_HOST vs SERVER_NAME:前者來自客戶端 Host 標頭(可偽造),後者來自伺服器設定(可信)。生產環境建議用 SERVER_NAME 或經白名單驗證的 HTTP_HOST。
  2. 反向代理 / Load Balancer:真實協定與端口可能藏在 HTTP_X_FORWARDED_PROTO、HTTP_X_FORWARDED_PORT,需信任代理並正確設定 trusted_proxies(Laravel/Symfony 等框架內建處理)。
  3. CLI 模式:$_SERVER['REQUEST_URI'] 等鍵不存在,需判斷 php_sapi_name() === 'cli' 避免報錯。
  4. URL 編碼:REQUEST_URI 為原始編碼,若需解碼路徑段落請用 rawurldecode()。

進階:URL 解析與重建

$url = 'https://user:pass@example.com:8080/path?query=value#fragment';
$parts = parse_url($url);
/*
[
  'scheme' => 'https',
  'host' => 'example.com',
  'port' => 8080,
  'user' => 'user',
  'pass' => 'pass',
  'path' => '/path',
  'query' => 'query=value',
  'fragment' => 'fragment'
]
*/

// 解析查詢字串為陣列
parse_str($parts['query'] ?? '', $queryArr);
// $queryArr = ['query' => 'value']

// 重建 URL(修改某參數)
$queryArr['page'] = 2;
$newQuery = http_build_query($queryArr);
$newUrl = $parts['scheme'] . '://' . $parts['host'] 
        . (isset($parts['port']) ? ':' . $parts['port'] : '')
        . $parts['path'] . '?' . $newQuery;

最佳實務封裝類別(單一職責)

final class CurrentUrl
{
    private string $scheme;
    private string $host;
    private int    $port;
    private string $path;
    private string $query;

    public static function fromGlobals(): self
    {
        $https = (!empty($_SERVER['HTTPS']) && $_SERVER['HTTPS'] !== 'off')
              || (($_SERVER['REQUEST_SCHEME'] ?? '') === 'https');
        $self = new self();
        $self->scheme = $https ? 'https' : 'http';
        $self->host   = $_SERVER['HTTP_HOST'] ?? $_SERVER['SERVER_NAME'] ?? 'localhost';
        $self->port   = (int)($_SERVER['SERVER_PORT'] ?? ($https ? 443 : 80));
        $self->path   = $_SERVER['REQUEST_URI'] ?? '/';
        if (($pos = strpos($self->path, '?')) !== false) {
            $self->query = substr($self->path, $pos + 1);
            $self->path  = substr($self->path, 0, $pos);
        } else {
            $self->query = '';
        }
        return $self;
    }

    public function full(): string
    {
        $host = $this->host;
        if (($this->scheme === 'http' && $this->port !== 80) ||
            ($this->scheme === 'https' && $this->port !== 443)) {
            if (strpos($host, ':') === false) $host .= ':' . $this->port;
        }
        return $this->scheme . '://' . $host . $this->path 
             . ($this->query ? '?' . $this->query : '');
    }

    public function domain(): string { return preg_replace('/:\d+$/', '', $this->host); }
    public function base(): string { return $this->scheme . '://' . $this->host; }
    public function path(): string { return $this->path; }
    public function query(): string { return $this->query; }
    public function queryArray(): array { parse_str($this->query, $arr); return $arr; }
}

// 使用
$url = CurrentUrl::fromGlobals();
echo $url->full();      // 完整 URL
echo $url->domain();    // 僅域名
echo $url->base();      // 基礎 URL

總結

掌握 $_SERVER 關鍵鍵值差異、正確處理 HTTPS 與非標準端口、注意代理環境下的 Header 信任鏈,即能可靠取得各種形式的 URL。建議封裝為工具類或使用框架內建 Request 物件,避免重複造輪子與漏洞。

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