HOWTO · PHP

在 PHP 中獲取標頭

本教學說明如何取得 URL 回應的 HTTP 標頭,以及 PHP 伺服器收到的 HTTP 請求標頭。

本頁內容

HTTP 標頭會在 HTTP 用戶端與伺服器之間傳遞中繼資料。請依照要檢查通訊哪一端來選擇 PHP 方法:get_headers() 會讀取 URL 請求的回應,而 $_SERVER 和請求標頭函式則會提供目前伺服器收到的資訊。

依照要檢查的標頭選擇 PHP 方法

若 PHP 程式需要檢查某個 URL 傳回的回應,請使用 get_headers()。若要檢查應用程式收到的傳入請求,可以從 $_SERVER 讀取指定值,或使用 apache_request_headers() 或 getallheaders() 取得一組標頭。如果這些函式無法使用或不適合目前情境,也可以篩選 $_SERVER 建立標頭清單。

這些來源代表通訊過程中的不同部分。Content-Type 這類回應標頭描述的是回應;User-Agent 這類請求標頭則是由用戶端傳來。應用程式能取得哪些值,可能會因請求內容和伺服器設定而異。

使用 get_headers() 取得 URL 的回應標頭

get_headers() 會向指定 URL 發出請求,並以陣列形式傳回回應標頭。第一個陣列項目通常包含 HTTP 狀態行,後面接著各標頭行。傳回的值會受到 URL、重新導向、伺服器回應和網路狀況影響,因此不要依賴固定不變的即時網站輸出。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

<?php
$url = 'https://example.com/';
$headers = @get_headers($url);

if ($headers === false) {
    echo "No response headers were returned.\n";
} else {
    foreach ($headers as $header) {
        echo $header, "\n";
    }
}

此範例需要可連線的 URL,以及 PHP 的 URL stream 支援;回應會依執行環境而異,因此不提供固定輸出。在應用程式程式碼中,若 URL 可能由使用者提供,請先驗證或限制 URL,並處理請求失敗的情況,不要假設結果一定是陣列。

從 $_SERVER 讀取單一請求標頭

PHP 通常會將傳入的請求標頭放在 HTTP_* 項目中,儲存於 $_SERVER。例如,使用者代理程式的值可能存放在 HTTP_USER_AGENT。這個陣列也包含其他伺服器與請求資訊,而且特定標頭的索引可能不存在。讀取可選值時,請提供預設值:

本節中的程式碼以及顯示的標籤或輸出仍為英文。

$userAgent = $_SERVER['HTTP_USER_AGENT'] ?? null;

請將這些值視為隨請求傳入的使用者輸入。在將它們用於判斷或輸出之前先進行驗證;若要呈現在頁面上,則應先跳脫處理。

使用 apache_request_headers() 或 getallheaders() 取得所有請求標頭

若執行環境提供 apache_request_headers(),它會以關聯陣列傳回收到的請求標頭。getallheaders() 也可用於相同的一般目的。兩者是否可用取決於 PHP 與伺服器環境;若程式必須在不同設定中執行,呼叫之前請先檢查函式是否存在。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

<?php
if (function_exists('getallheaders')) {
    $headers = getallheaders();
} elseif (function_exists('apache_request_headers')) {
    $headers = apache_request_headers();
} else {
    $headers = [];
}

foreach ($headers as $name => $value) {
    echo $name, ': ', $value, "\n";
}

請透過 Web 請求,在提供其中一個函式的環境中執行這段程式。在命令列程序中,可能沒有傳入的 HTTP 請求或適用的伺服器 API,因此清單可能是空的。

從 $_SERVER 建立請求標頭清單

若需要替代清單,可篩選 $_SERVER 中以 HTTP_ 開頭的索引,接著移除該前綴,並將底線轉換為連字號。這項篩選只會選取符合條件的項目,不會涵蓋所有伺服器變數。有些請求資料,例如內容長度或內容類型,可能存放在 $_SERVER 中其他不帶 HTTP_ 前綴的索引。

本節中的程式碼以及顯示的標籤或輸出仍為英文。

<?php
function requestHeadersFromServer(array $server): array
{
    $headers = [];
    foreach ($server as $key => $value) {
        if (strncmp($key, 'HTTP_', 5) !== 0) {
            continue;
        }
        $name = str_replace('_', '-', strtolower(substr($key, 5)));
        $headers[$name] = $value;
    }
    return $headers;
}

$headers = requestHeadersFromServer($_SERVER);
foreach ($headers as $name => $value) {
    echo $name, ': ', $value, "\n";
}

這項轉換會產生 user-agent 這類易讀名稱,但無法還原伺服器未提供或存放在其他索引下的標頭。HTTP 標頭名稱不區分大小寫,因此比較名稱時,應用程式不應依賴特定的大小寫形式。顯示的值會依傳入請求與伺服器環境而異。