PHP 超全域變數 (Superglobals)

超全域變數是 PHP 預定義的變數,在任何地方都可以存取,不需要使用 global 關鍵字。

超全域變數列表

變數說明
$_GETURL 查詢字串參數
$_POSTPOST 請求資料
$_REQUESTGET + POST + COOKIE
$_FILES上傳的檔案
$_COOKIECookie 資料
$_SESSIONSession 資料
$_SERVER伺服器和執行環境資訊
$_ENV環境變數
$GLOBALS所有全域變數的參考

$_GET

$_GET 用於接收透過 URL 查詢字串傳遞的資料。當使用者在網址後面加上 ?key=value 的參數,PHP 會自動將這些參數放入 $_GET 陣列中。這種方式常用於搜尋功能、分頁、篩選等不敏感資料的傳遞。

<?php
// URL: example.com/page.php?name=Alice&age=25

echo $_GET['name'];  // Alice
echo $_GET['age'];   // 25

// 安全存取
$name = $_GET['name'] ?? 'Guest';
?>

處理同名多個參數

在 URL 中,如果出現多個同名的參數(例如 ?id=1&id=2&id=3),PHP 預設只會取得最後一個值。如果你希望一次取得所有值,必須在參數名稱後面加上中括號 [],這樣 PHP 就會將其解析為陣列。

<?php
// URL: example.com/page.php?id[]=1&id[]=2&id[]=3

// PHP 會將 id 解析為陣列
$ids = $_GET['id'];

foreach ($ids as $id) {
    echo $id . " ";  // 輸出: 1 2 3
}

// 常用於複選框 (Checkbox) 的表單提交
?>

$_POST

$_POST 用於接收透過 HTTP POST 方法提交的表單資料。與 GET 不同,POST 資料不會顯示在網址中,適合傳送密碼、個人資料等敏感資訊。資料大小也沒有 URL 長度的限制。

<?php
// 表單提交後
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
    $name = $_POST['name'] ?? '';
    $email = $_POST['email'] ?? '';
}
?>

<form method="POST">
    <input type="text" name="name">
    <input type="email" name="email">
    <button type="submit">送出</button>
</form>

$_FILES

$_FILES 用於處理透過 HTTP POST 方法上傳的檔案資訊。它是一個二維陣列,包含了上傳檔案的名稱、類型、大小、暫存路徑以及錯誤代碼。

<?php
if ($_SERVER['REQUEST_METHOD'] === 'POST' && isset($_FILES['upload_file'])) {
    $file = $_FILES['upload_file'];

    echo $file['name'];     // 原始檔名
    echo $file['type'];     // 檔案類型 (例如 image/jpeg)
    echo $file['tmp_name']; // 伺服器上的暫存路徑
    echo $file['error'];    // 錯誤代碼 (0 代表成功)
    echo $file['size'];     // 檔案大小 (bytes)
}
?>
關於檔案上傳的詳細實作與安全性,請參考 PHP 檔案上傳 教學。

$_SERVER

$_SERVER 包含了伺服器和 HTTP 請求的相關資訊,例如請求方法、使用者 IP、瀏覽器資訊、腳本路徑等。這些資訊由網頁伺服器提供,對於處理請求和除錯非常有用。

<?php
// 常用的 $_SERVER 變數
echo $_SERVER['REQUEST_METHOD'];   // GET 或 POST
echo $_SERVER['REQUEST_URI'];      // /path/to/page.php?query=1
echo $_SERVER['HTTP_HOST'];        // example.com
echo $_SERVER['HTTP_USER_AGENT'];  // 瀏覽器資訊
echo $_SERVER['REMOTE_ADDR'];      // 使用者 IP
echo $_SERVER['DOCUMENT_ROOT'];    // 網站根目錄
echo $_SERVER['SCRIPT_FILENAME'];  // 目前腳本的完整路徑
echo $_SERVER['PHP_SELF'];         // 目前腳本名稱
echo $_SERVER['QUERY_STRING'];     // 查詢字串
?>

$_REQUEST

$_REQUEST 是一個方便的超全域變數,它合併了 $_GET$_POST$_COOKIE 的內容。雖然使用起來方便,但因為無法明確知道資料來源,在安全性考量下,建議直接使用對應的變數。

<?php
// 可以從 GET 或 POST 取得
$action = $_REQUEST['action'] ?? 'default';
?>
建議使用 $_GET$_POST 而非 $_REQUEST,這樣更明確知道資料來源。

$GLOBALS

$GLOBALS 是一個關聯陣列,包含了目前腳本中所有全域變數的參考。透過這個陣列,你可以在函數內存取或修改全域變數,而不需要使用 global 關鍵字。

<?php
$x = 10;
$y = 20;

function test() {
    echo $GLOBALS['x'];      // 10
    echo $GLOBALS['y'];      // 20
    $GLOBALS['z'] = 30;      // 建立新的全域變數
}

test();
echo $z;  // 30
?>

安全處理

處理超全域變數時,安全性是最重要的考量。永遠不要信任來自使用者的輸入,因為這可能導致跨站腳本攻擊 (XSS) 或 SQL 注入。

預防 XSS 攻擊

當你要將超全域變數中的資料輸出到 HTML 頁面時,必須使用 htmlspecialchars() 進行轉義,防止惡意程式碼執行。

<?php
// 錯誤示範:直接輸出 (危險!)
// echo $_GET['name'];

// 正確做法:轉義後輸出
echo htmlspecialchars($_GET['name'] ?? '', ENT_QUOTES, 'UTF-8');
?>

驗證與過濾

使用 filter_input()filter_var() 來驗證資料格式。

<?php
// 驗證和清理輸入
$name = filter_input(INPUT_GET, 'name', FILTER_SANITIZE_SPECIAL_CHARS);
$email = filter_input(INPUT_POST, 'email', FILTER_VALIDATE_EMAIL);
$age = filter_input(INPUT_GET, 'age', FILTER_VALIDATE_INT);

// 使用 ?? 提供預設值
$page = $_GET['page'] ?? 1;

// 檢查是否存在
if (isset($_POST['submit'])) {
    // 處理表單
}

// 驗證請求方法
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
    http_response_code(405);
    exit('Method Not Allowed');
}
?>

$_SERVER['PHP_SELF'] 的安全性

$_SERVER['PHP_SELF'] 常用於表單的 action 屬性,但它存在被注入惡意程式碼的風險。

<!-- 危險做法 -->
<form method="post" action="<?php echo $_SERVER['PHP_SELF']; ?>">

<!-- 安全做法:使用 htmlspecialchars() -->
<form method="post" action="<?php echo htmlspecialchars($_SERVER['PHP_SELF']); ?>">

實際範例

<?php
// 簡單的頁面路由
$page = $_GET['page'] ?? 'home';

switch ($page) {
    case 'home':
        include 'pages/home.php';
        break;
    case 'about':
        include 'pages/about.php';
        break;
    default:
        http_response_code(404);
        include 'pages/404.php';
}
?>