三大超全局變量對比
| 變量 | 來源 | 適用場景 | 安全性 |
$_GET |
URL 查詢字符串 ?key=val |
搜尋、分頁、排序、幂等操作 |
可見、可被緩存、CSRF 風險低 |
$_POST |
HTTP Body(application/x-www-form-urlencoded / multipart/form-data) |
表單提交、狀態變更、敏感數據 |
不在 URL 中、需配合 CSRF Token |
$_REQUEST |
$_GET + $_POST + $_COOKIE(受 request_order 影響) |
極少數兼容舊代碼場景 |
不推薦:來源模糊、Cookie 覆蓋風險 |
基本用法
<?php
// 獲取單個值(推薦過濾輸入)
$username = filter_input(INPUT_POST, 'username', FILTER_SANITIZE_SPECIAL_CHARS);
$age = filter_input(INPUT_POST, 'age', FILTER_VALIDATE_INT);
$tags = filter_input(INPUT_POST, 'tags', FILTER_DEFAULT, FILTER_REQUIRE_ARRAY);
// 判斷是否提交
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 處理邏輯
}
表單元素對應獲取方式
| HTML 元素 | name 屬性 | PHP 獲取代碼 | 返回類型 |
<input type="text"> |
username |
$_POST['username'] |
string |
<input type="password"> |
password |
$_POST['password'] |
string |
<select> (單選) |
city |
$_POST['city'] |
string |
<select multiple> |
cities[] |
$_POST['cities'] |
array |
<input type="checkbox"> (多個同名) |
hobby[] |
$_POST['hobby'] |
array |
<input type="radio"> (同名分組) |
gender |
$_POST['gender'] |
string (被選值) |
<input type="file"> |
avatar |
$_FILES['avatar'] |
array (tmp_name, size, error...) |
完整表單處理範例
<?php
// process.php
declare(strict_types=1);
if ($_SERVER['REQUEST_METHOD'] !== 'POST') {
http_response_code(405);
exit('僅接受 POST 請求');
}
// 1. CSRF 驗證(簡化版)
if (!hash_equals($_SESSION['csrf_token'] ?? '', $_POST['csrf_token'] ?? '')) {
http_response_code(403);
exit('CSRF 驗證失敗');
}
// 2. 定義驗證規則
$rules = [
'username' => ['required' => true, 'filter' => FILTER_SANITIZE_SPECIAL_CHARS, 'min' => 3, 'max' => 20],
'email' => ['required' => true, 'filter' => FILTER_VALIDATE_EMAIL],
'age' => ['required' => false, 'filter' => FILTER_VALIDATE_INT, 'options' => ['min_range' => 1, 'max_range' => 120]],
'hobby' => ['required' => false, 'filter' => FILTER_DEFAULT, 'flags' => FILTER_REQUIRE_ARRAY],
'gender' => ['required' => true, 'filter' => FILTER_SANITIZE_SPECIAL_CHARS],
'bio' => ['required' => false, 'filter' => FILTER_SANITIZE_SPECIAL_CHARS],
];
// 3. 批量過濾驗證
$inputs = filter_input_array(INPUT_POST, array_column($rules, 'filter'));
$errors = [];
foreach ($rules as $field => $rule) {
$value = $inputs[$field] ?? null;
if ($rule['required'] && ($value === null || $value === '' || $value === false)) {
$errors[$field] = '此欄位為必填';
continue;
}
if ($value === false) { // FILTER_VALIDATE_* 失敗返回 false
$errors[$field] = '格式不正確';
}
// 長度檢查
if (isset($rule['min']) && mb_strlen($value) < $rule['min']) {
$errors[$field] = "最少 {$rule['min']} 字符";
}
if (isset($rule['max']) && mb_strlen($value) > $rule['max']) {
$errors[$field] = "最多 {$rule['max']} 字符";
}
}
if ($errors) {
// 返回錯誤(API 或重定向回表單攜帶錯誤)
exit(json_encode(['code' => 422, 'errors' => $errors], JSON_UNESCAPED_UNICODE));
}
// 4. 業務處理(此處 $inputs 已為安全數據)
// $userId = User::create($inputs);
// 重定向防重複提交
header('Location: success.php');
exit;
HTML 表單模板(配合上述處理)
<form action="process.php" method="post" enctype="multipart/form-data" novalidate>
<input type="hidden" name="csrf_token" value="<?php echo $_SESSION['csrf_token'] = bin2hex(random_bytes(32)); ?>">
<div>
<label>用戶名:<input type="text" name="username" required minlength="3" maxlength="20"></label>
</div>
<div>
<label>郵箱:<input type="email" name="email" required></label>
</div>
<div>
<label>年齡:<input type="number" name="age" min="1" max="120"></label>
</div>
<div>
<label>性別:
<input type="radio" name="gender" value="male" required> 男
<input type="radio" name="gender" value="female"> 女
</label>
</div>
<div>
<label>愛好:
<input type="checkbox" name="hobby[]" value="coding"> 编程
<input type="checkbox" name="hobby[]" value="reading"> 閱讀
<input type="checkbox" name="hobby[]" value="sports"> 運動
</label>
</div>
<div>
<label>簡介:<textarea name="bio" maxlength="500"></textarea></label>
</div>
<button type="submit">提交</button>
</form>
安全最佳實踐總結
- 永不信任輸入:所有
$_GET/$_POST 經 filter_input 或驗證器處理後再使用。
- 輸出轉義:HTML 上下文用
htmlspecialchars(),JS 用 json_encode(),SQL 用預處理語句。
- CSRF 保護:狀態改變操作必須驗證 Token。
- 文件上傳:驗證 MIME、副檔名、大小、掃描病毒、重命名存儲、禁用腳本執行權限。
- 最小權限原則:只獲取業務需要的字段,避免
$_REQUEST 或 extract($_POST)。
現代框架中的對應
- Laravel:
$request->validated() / FormRequest
- Symfony:
$form->handleRequest($request) + Validator 組件
- ThinkPHP:
Validate::check($data)
- 原生 PHP:
filter_input_array + 自定義驗證類(如本文範例)
掌握原生表單處理細節,能讓你在任何框架或無框架環境下編寫安全、健壯的輸入處理代碼。