PHP 表單處理 (Form Handling)
PHP 可以接收和處理 HTML 表單提交的資料。
基本表單
<form action="process.php" method="POST">
<label>名稱:<input type="text" name="name"></label>
<label>Email:<input type="email" name="email"></label>
<button type="submit">送出</button>
</form>
<?php
// process.php
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
$name = $_POST['name'] ?? '';
$email = $_POST['email'] ?? '';
echo "名稱:$name<br>";
echo "Email:$email";
}
?>
GET vs POST
| 特性 | GET | POST |
|---|---|---|
| 資料位置 | URL 查詢字串 | HTTP 請求主體 |
| 資料大小 | 有限制(約 2KB) | 較大 |
| 安全性 | 較低(會顯示在 URL) | 較高 |
| 適用場合 | 搜尋、篩選 | 登入、表單提交 |
表單驗證
<?php
$errors = [];
$data = [];
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
// 清理輸入
$name = trim($_POST['name'] ?? '');
$email = trim($_POST['email'] ?? '');
$age = $_POST['age'] ?? '';
// 驗證名稱
if (empty($name)) {
$errors['name'] = '名稱不能為空';
} elseif (strlen($name) < 2) {
$errors['name'] = '名稱至少 2 個字元';
}
// 驗證 Email
if (empty($email)) {
$errors['email'] = 'Email 不能為空';
} elseif (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
$errors['email'] = 'Email 格式不正確';
}
// 驗證年齡
if (!empty($age)) {
$age = filter_var($age, FILTER_VALIDATE_INT);
if ($age === false || $age < 0 || $age > 150) {
$errors['age'] = '請輸入有效的年齡';
}
}
// 如果沒有錯誤
if (empty($errors)) {
$data = ['name' => $name, 'email' => $email, 'age' => $age];
// 處理資料...
}
}
?>
<form method="POST">
<div>
<label>名稱:</label>
<input type="text" name="name" value="<?= htmlspecialchars($name ?? '') ?>">
<?php if (isset($errors['name'])): ?>
<span class="error"><?= $errors['name'] ?></span>
<?php endif; ?>
</div>
<div>
<label>Email:</label>
<input type="email" name="email" value="<?= htmlspecialchars($email ?? '') ?>">
<?php if (isset($errors['email'])): ?>
<span class="error"><?= $errors['email'] ?></span>
<?php endif; ?>
</div>
<button type="submit">送出</button>
</form>
不同的輸入類型
<?php
// 單選框
$gender = $_POST['gender'] ?? '';
// 複選框
$hobbies = $_POST['hobbies'] ?? [];
// 下拉選單
$country = $_POST['country'] ?? '';
// 文字區域
$message = $_POST['message'] ?? '';
?>
<form method="POST">
<!-- 單選框 -->
<label><input type="radio" name="gender" value="male"> 男</label>
<label><input type="radio" name="gender" value="female"> 女</label>
<!-- 複選框 -->
<label><input type="checkbox" name="hobbies[]" value="reading"> 閱讀</label>
<label><input type="checkbox" name="hobbies[]" value="gaming"> 遊戲</label>
<label><input type="checkbox" name="hobbies[]" value="sports"> 運動</label>
<!-- 下拉選單 -->
<select name="country">
<option value="">請選擇</option>
<option value="tw">台灣</option>
<option value="us">美國</option>
<option value="jp">日本</option>
</select>
<!-- 文字區域 -->
<textarea name="message"></textarea>
<button type="submit">送出</button>
</form>
CSRF 保護
<?php
session_start();
// 產生 Token
if (empty($_SESSION['csrf_token'])) {
$_SESSION['csrf_token'] = bin2hex(random_bytes(32));
}
// 驗證 Token
if ($_SERVER['REQUEST_METHOD'] === 'POST') {
if (!isset($_POST['csrf_token']) ||
$_POST['csrf_token'] !== $_SESSION['csrf_token']) {
die('CSRF 驗證失敗');
}
}
?>
<form method="POST">
<input type="hidden" name="csrf_token"
value="<?= $_SESSION['csrf_token'] ?>">
<!-- 其他欄位 -->
</form>
XSS 防護
<?php
// 永遠使用 htmlspecialchars 輸出使用者資料
$name = $_POST['name'] ?? '';
?>
<!-- 安全輸出 -->
<p>名稱:<?= htmlspecialchars($name, ENT_QUOTES, 'UTF-8') ?></p>
<!-- 危險:直接輸出 -->
<!-- <p>名稱:<?= $name ?></p> -->